Add TPO2
This commit is contained in:
parent
e675f7593d
commit
ff5f2319ec
11
TP02/ITE/ITE.g4
Normal file
11
TP02/ITE/ITE.g4
Normal file
@ -0,0 +1,11 @@
|
||||
grammar ITE;
|
||||
|
||||
prog: stmt EOF;
|
||||
|
||||
stmt : ifStmt | ID ;
|
||||
|
||||
ifStmt : 'if' ID 'then' thenstmt=stmt ('else' elsestmt=stmt)?;
|
||||
|
||||
|
||||
ID : [a-zA-Z]+;
|
||||
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
|
17
TP02/ITE/Makefile
Normal file
17
TP02/ITE/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
MAINFILE = main
|
||||
PACKAGE = ITE
|
||||
|
||||
ifndef ANTLR4
|
||||
$(error variable ANTLR4 is not set)
|
||||
endif
|
||||
|
||||
default: $(PACKAGE)Parser.py
|
||||
|
||||
$(PACKAGE)Parser.py: $(PACKAGE).g4
|
||||
$(ANTLR4) $^ -Dlanguage=Python3
|
||||
|
||||
run: $(MAINFILE).py $(PACKAGE)Parser.py
|
||||
python3 $<
|
||||
|
||||
clean:
|
||||
rm -rf *~ $(PACKAGE)*.py $(PACKAGE)*.pyc *.interp *.tokens __pycache*
|
21
TP02/ITE/main.py
Normal file
21
TP02/ITE/main.py
Normal file
@ -0,0 +1,21 @@
|
||||
from antlr4 import InputStream
|
||||
from antlr4 import CommonTokenStream
|
||||
|
||||
# include to use the generated lexer and parser
|
||||
from ITELexer import ITELexer
|
||||
from ITEParser import ITEParser
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
lexer = ITELexer(InputStream(sys.stdin.read()))
|
||||
stream = CommonTokenStream(lexer)
|
||||
parser = ITEParser(stream)
|
||||
parser.prog()
|
||||
print("Finished")
|
||||
|
||||
|
||||
# warns pb if py file is included in others
|
||||
if __name__ == '__main__':
|
||||
main()
|
27
TP02/ariteval/Arit.g4
Normal file
27
TP02/ariteval/Arit.g4
Normal file
@ -0,0 +1,27 @@
|
||||
grammar Arit;
|
||||
|
||||
// MIF08@Lyon1 and CAP@ENSL, arit evaluator
|
||||
|
||||
@header {
|
||||
# header - mettre les déclarations globales
|
||||
import sys
|
||||
idTab = {};
|
||||
|
||||
class UnknownIdentifier(Exception):
|
||||
pass
|
||||
|
||||
class DivByZero(Exception):
|
||||
pass
|
||||
|
||||
}
|
||||
|
||||
prog: ID {print("prog = "+str($ID.text));} ;
|
||||
|
||||
|
||||
COMMENT
|
||||
: '//' ~[\r\n]* -> skip
|
||||
;
|
||||
|
||||
ID : ('a'..'z'|'A'..'Z')+;
|
||||
INT: '0'..'9'+;
|
||||
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
|
36
TP02/ariteval/Makefile
Normal file
36
TP02/ariteval/Makefile
Normal file
@ -0,0 +1,36 @@
|
||||
MAINFILE = arit
|
||||
PACKAGE = Arit
|
||||
|
||||
ifndef ANTLR4
|
||||
$(error variable ANTLR4 is not set)
|
||||
endif
|
||||
|
||||
$(PACKAGE)Listener.py $(PACKAGE)Lexer.py $(PACKAGE)Lexer.tokens $(PACKAGE)Parser.py $(PACKAGE).tokens: $(PACKAGE).g4
|
||||
$(ANTLR4) $< -Dlanguage=Python3
|
||||
|
||||
main-deps: $(PACKAGE)Lexer.py $(PACKAGE)Parser.py
|
||||
|
||||
#use pytest !!
|
||||
|
||||
run: $(MAINFILE).py main-deps
|
||||
python3 $<
|
||||
|
||||
TESTFILE=tests/test01.txt
|
||||
|
||||
print-lisp: $(MAINFILE).py main-deps
|
||||
python3 $< $(TESTFILE) --lisp
|
||||
|
||||
print-tree: $(MAINFILE).py main-deps
|
||||
python3 $< $(TESTFILE) --lisp --debug
|
||||
|
||||
test: test_ariteval.py main-deps
|
||||
python3 -m pytest -v $<
|
||||
|
||||
tar: clean
|
||||
dir=$$(basename "$$PWD") && cd .. && \
|
||||
tar cvfz "$$dir.tgz" --exclude="*.riscv" --exclude=".git" --exclude=".pytest_cache" \
|
||||
--exclude="htmlcov" --exclude="*.dot" --exclude="*.pdf" "$$dir"
|
||||
@echo "Created ../$$dir.tgz"
|
||||
|
||||
clean:
|
||||
rm -rf *~ $(PACKAGE)*.py $(PACKAGE)*.pyc *.tokens __pycache* .cache *.interp *.java *.class *.dot *.dot.pdf
|
66
TP02/ariteval/arit.py
Normal file
66
TP02/ariteval/arit.py
Normal file
@ -0,0 +1,66 @@
|
||||
#! /usr/bin/env python3
|
||||
"""
|
||||
Usage:
|
||||
python3 arit.py <filename>
|
||||
"""
|
||||
# Main file for MIF08 - Lab03 - 2018, changed in 2022
|
||||
|
||||
from AritLexer import AritLexer
|
||||
from AritParser import AritParser, UnknownIdentifier, DivByZero
|
||||
from antlr4 import FileStream, CommonTokenStream, StdinStream
|
||||
from antlr4.tree.Trees import Trees
|
||||
from antlr4.Utils import escapeWhitespace
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
def getNodeText(node, parser):
|
||||
return escapeWhitespace(Trees.getNodeText(node, recog=parser),
|
||||
True).replace('\\', '\\\\')
|
||||
|
||||
|
||||
def _toDot(t, g, parser):
|
||||
for c in Trees.getChildren(t):
|
||||
g.node(str(id(c)), getNodeText(c, parser))
|
||||
g.edge(str(id(t)), str(id(c)))
|
||||
_toDot(c, g, parser)
|
||||
|
||||
|
||||
def toDot(t, parser):
|
||||
from graphviz import Digraph
|
||||
g = Digraph()
|
||||
g.node(str(id(t)), getNodeText(t, parser))
|
||||
_toDot(t, g, parser)
|
||||
g.render("tree.dot", view=True)
|
||||
|
||||
|
||||
def main(inputname, lisp, debug):
|
||||
if inputname is None:
|
||||
lexer = AritLexer(StdinStream())
|
||||
else:
|
||||
lexer = AritLexer(FileStream(inputname))
|
||||
stream = CommonTokenStream(lexer)
|
||||
parser = AritParser(stream)
|
||||
try:
|
||||
tree = parser.prog()
|
||||
if lisp:
|
||||
print(tree.toStringTree(tree, parser))
|
||||
if debug:
|
||||
toDot(tree, parser)
|
||||
except UnknownIdentifier as exc: # Parser's exception
|
||||
print('{} is undefined'.format(exc.args[0]))
|
||||
exit(1)
|
||||
except DivByZero:
|
||||
print('Division by zero')
|
||||
exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='AritEval lab')
|
||||
parser.add_argument('filename', type=str, nargs='?', help='Source file.')
|
||||
parser.add_argument('--lisp', default=False, action='store_true',
|
||||
help="Print parse tree in Lisp format")
|
||||
parser.add_argument('--debug', default=False, action='store_true',
|
||||
help="Print parse tree graphically")
|
||||
args = parser.parse_args()
|
||||
main(args.filename, args.lisp, args.debug)
|
28
TP02/ariteval/test_ariteval.py
Executable file
28
TP02/ariteval/test_ariteval.py
Executable file
@ -0,0 +1,28 @@
|
||||
#! /usr/bin/env python3
|
||||
import pytest
|
||||
import glob
|
||||
import sys
|
||||
from test_expect_pragma import TestExpectPragmas
|
||||
|
||||
ALL_FILES = glob.glob('./tests/hello*.txt')
|
||||
|
||||
# only test programs of these shapes!
|
||||
# ALL_FILES = glob.glob('./tests/test*.txt')
|
||||
# + glob.glob('./tests/bad*.txt')
|
||||
|
||||
EVAL = 'arit.py'
|
||||
|
||||
|
||||
class TestEVAL(TestExpectPragmas):
|
||||
def evaluate(self, file):
|
||||
return self.run_command(['python3', EVAL, file])
|
||||
|
||||
@pytest.mark.parametrize('filename', ALL_FILES)
|
||||
def test_expect(self, filename):
|
||||
expect = self.get_expect(filename)
|
||||
eval = self.evaluate(filename)
|
||||
assert expect == eval
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main(sys.argv)
|
95
TP02/ariteval/test_expect_pragma.py
Normal file
95
TP02/ariteval/test_expect_pragma.py
Normal file
@ -0,0 +1,95 @@
|
||||
import collections
|
||||
import re
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
testresult = collections.namedtuple('testresult', ['exitcode', 'output'])
|
||||
|
||||
|
||||
def cat(filename):
|
||||
with open(filename, "rb") as f:
|
||||
for line in f:
|
||||
sys.stdout.buffer.write(line)
|
||||
|
||||
|
||||
class TestExpectPragmas(object):
|
||||
"""Base class for tests that read the expected result as annotations
|
||||
in test files.
|
||||
|
||||
get_expect(file) will parse the file, looking EXPECT and EXITCODE
|
||||
pragmas.
|
||||
|
||||
run_command(command) is a wrapper around subprocess.check_output()
|
||||
that extracts the output and exit code.
|
||||
|
||||
"""
|
||||
def get_expect(self, filename):
|
||||
"""Parse "filename" looking for EXPECT and EXITCODE annotations.
|
||||
|
||||
Look for a line "EXPECTED" (possibly with whitespaces and
|
||||
comments). Text after this "EXPECTED" line is the expected
|
||||
output.
|
||||
|
||||
The file may also contain a line like "EXITCODE <n>" where <n>
|
||||
is an integer, and is the expected exitcode of the command.
|
||||
|
||||
The result is cached to avoid re-parsing the file multiple
|
||||
times.
|
||||
"""
|
||||
if filename not in self.__expect:
|
||||
self.__expect[filename] = self._extract_expect(filename)
|
||||
return self.__expect[filename]
|
||||
|
||||
def remove(self, file):
|
||||
"""Like os.remove(), but ignore errors, e.g. don't complain if the
|
||||
file doesn't exist.
|
||||
"""
|
||||
try:
|
||||
os.remove(file)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def run_command(self, cmd):
|
||||
"""Run the command cmd (given as [command, arg1, arg2, ...]), and
|
||||
return testresult(exitcode=..., output=...) containing the
|
||||
exit code of the command it its standard output + standard error.
|
||||
"""
|
||||
try:
|
||||
output = subprocess.check_output(cmd, timeout=60,
|
||||
stderr=subprocess.STDOUT)
|
||||
exitcode = 0
|
||||
except subprocess.CalledProcessError as e:
|
||||
output = e.output
|
||||
exitcode = e.returncode
|
||||
return testresult(exitcode=exitcode, output=output.decode())
|
||||
|
||||
__expect = {}
|
||||
|
||||
def _extract_expect(self, file):
|
||||
exitcode = 0
|
||||
inside_expected = False
|
||||
expected_lines = []
|
||||
with open(file, encoding="utf-8") as f:
|
||||
for line in f.readlines():
|
||||
# Ignore non-comments
|
||||
if not re.match(r'\s*//', line):
|
||||
continue
|
||||
# Cleanup comment start and whitespaces
|
||||
line = re.sub(r'\s*//\s*', '', line)
|
||||
line = re.sub(r'\s*$', '', line)
|
||||
|
||||
if line == 'END EXPECTED':
|
||||
inside_expected = False
|
||||
elif line.startswith('EXITCODE'):
|
||||
words = line.split(' ')
|
||||
assert len(words) == 2
|
||||
exitcode = int(words[1])
|
||||
elif line == 'EXPECTED':
|
||||
inside_expected = True
|
||||
elif inside_expected:
|
||||
expected_lines.append(line)
|
||||
|
||||
expected_lines.append('')
|
||||
return testresult(exitcode=exitcode,
|
||||
output=os.linesep.join(expected_lines))
|
4
TP02/ariteval/tests/bad01.txt
Normal file
4
TP02/ariteval/tests/bad01.txt
Normal file
@ -0,0 +1,4 @@
|
||||
a = 4 +b ;
|
||||
// EXPECTED
|
||||
// b is undefined
|
||||
// EXITCODE 1
|
3
TP02/ariteval/tests/hello01.txt
Normal file
3
TP02/ariteval/tests/hello01.txt
Normal file
@ -0,0 +1,3 @@
|
||||
Hello
|
||||
// EXPECTED
|
||||
// prog = Hello
|
10
TP02/ariteval/tests/test01.txt
Normal file
10
TP02/ariteval/tests/test01.txt
Normal file
@ -0,0 +1,10 @@
|
||||
20 + 22;
|
||||
a = 4;
|
||||
a + 2;
|
||||
a * 5;
|
||||
|
||||
// EXPECTED
|
||||
// 20+22 = 42
|
||||
// a now equals 4
|
||||
// a+2 = 6
|
||||
// a*5 = 20
|
1
TP02/demo_files/ex1/.gitignore
vendored
Normal file
1
TP02/demo_files/ex1/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/Example1.py
|
9
TP02/demo_files/ex1/Example1.g4
Normal file
9
TP02/demo_files/ex1/Example1.g4
Normal file
@ -0,0 +1,9 @@
|
||||
//define a lexical analyser called Example1
|
||||
|
||||
lexer grammar Example1;
|
||||
|
||||
OP : '+'| '*' | '-' | '/' ;
|
||||
DIGIT : [0-9] ;
|
||||
LETTER : [A-Za-z] ;
|
||||
ID : LETTER (LETTER | DIGIT)* ; // match idents
|
||||
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
|
17
TP02/demo_files/ex1/Makefile
Normal file
17
TP02/demo_files/ex1/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
MAINFILE = main
|
||||
PACKAGE = Example1
|
||||
|
||||
ifndef ANTLR4
|
||||
$(error variable ANTLR4 is not set)
|
||||
endif
|
||||
|
||||
default: $(PACKAGE).py
|
||||
|
||||
$(PACKAGE).py: $(PACKAGE).g4
|
||||
$(ANTLR4) $^ -Dlanguage=Python3
|
||||
|
||||
run: $(MAINFILE).py $(PACKAGE)*.py
|
||||
python3 $<
|
||||
|
||||
clean:
|
||||
rm -rf *~ $(PACKAGE)*.py $(PACKAGE)*.pyc *.interp *.tokens __pycache*
|
25
TP02/demo_files/ex1/main.py
Normal file
25
TP02/demo_files/ex1/main.py
Normal file
@ -0,0 +1,25 @@
|
||||
from antlr4 import InputStream
|
||||
from antlr4 import CommonTokenStream
|
||||
from Example1 import Example1
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
# InputStream reads characters (from stdin in our case)
|
||||
input_stream = InputStream(sys.stdin.read())
|
||||
# The generated lexer groups characters into Tokens ...
|
||||
lexer = Example1(input_stream)
|
||||
# ... and the stream of Tokens is managed by the TokenStream.
|
||||
stream = CommonTokenStream(lexer)
|
||||
|
||||
# Display the token stream
|
||||
stream.fill() # needed to get stream.tokens (otherwise lazily filled-in)
|
||||
for t in stream.tokens:
|
||||
print(t)
|
||||
print("Finished")
|
||||
|
||||
|
||||
# warns pb if py file is included in others
|
||||
if __name__ == '__main__':
|
||||
main()
|
17
TP02/demo_files/ex2/Example2.g4
Normal file
17
TP02/demo_files/ex2/Example2.g4
Normal file
@ -0,0 +1,17 @@
|
||||
//define a tiny grammar for arith expressions with identifiers
|
||||
|
||||
grammar Example2;
|
||||
|
||||
full_expr: expr ';' EOF ;
|
||||
|
||||
expr: expr OP expr
|
||||
| ID {print('oh an id : '+$ID.text)}
|
||||
| INT
|
||||
;
|
||||
|
||||
OP : '+'| '*' | '-' | '/' ;
|
||||
|
||||
|
||||
INT : '0'..'9'+ ;
|
||||
ID : ('a'..'z'|'A'..'Z')+ ;
|
||||
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
|
17
TP02/demo_files/ex2/Makefile
Normal file
17
TP02/demo_files/ex2/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
MAINFILE = main
|
||||
PACKAGE = Example2
|
||||
|
||||
ifndef ANTLR4
|
||||
$(error variable ANTLR4 is not set)
|
||||
endif
|
||||
|
||||
default: $(PACKAGE)Parser.py
|
||||
|
||||
$(PACKAGE)Parser.py: $(PACKAGE).g4
|
||||
$(ANTLR4) $^ -Dlanguage=Python3
|
||||
|
||||
run: $(MAINFILE).py $(PACKAGE)Parser.py
|
||||
python3 $<
|
||||
|
||||
clean:
|
||||
rm -rf *~ $(PACKAGE)*.py $(PACKAGE)*.pyc *.interp *.tokens __pycache*
|
22
TP02/demo_files/ex2/main.py
Normal file
22
TP02/demo_files/ex2/main.py
Normal file
@ -0,0 +1,22 @@
|
||||
from antlr4 import InputStream
|
||||
from antlr4 import CommonTokenStream
|
||||
|
||||
# include to use the generated lexer and parser
|
||||
from Example2Lexer import Example2Lexer
|
||||
from Example2Parser import Example2Parser
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
input_stream = InputStream(sys.stdin.read())
|
||||
lexer = Example2Lexer(input_stream)
|
||||
stream = CommonTokenStream(lexer)
|
||||
parser = Example2Parser(stream)
|
||||
parser.full_expr() # We want to recognize full_expr in grammar Example2
|
||||
print("Finished")
|
||||
|
||||
|
||||
# warns pb if py file is included in others
|
||||
if __name__ == '__main__':
|
||||
main()
|
18
TP02/demo_files/ex3/Example3.g4
Normal file
18
TP02/demo_files/ex3/Example3.g4
Normal file
@ -0,0 +1,18 @@
|
||||
//define a tiny grammar with attributes for arith expressions with identifiers
|
||||
|
||||
grammar Example3;
|
||||
|
||||
full_expr: e0=expr ';' EOF {print($e0.text + " has " + str($e0.count) + " operators!")} ;
|
||||
|
||||
expr returns [int count]: // expr has an integer attribute called count
|
||||
| e0=expr OP e1=expr {$count = $e0.count + $e1.count + 1} // name sub-parts and access their attributes
|
||||
| ID {$count = 0}
|
||||
| INT {$count = 0}
|
||||
;
|
||||
|
||||
OP : '+'| '*' | '-' | '/' ;
|
||||
|
||||
|
||||
INT : '0'..'9'+ ;
|
||||
ID : ('a'..'z'|'A'..'Z')+ ;
|
||||
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
|
17
TP02/demo_files/ex3/Makefile
Normal file
17
TP02/demo_files/ex3/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
MAINFILE = main
|
||||
PACKAGE = Example3
|
||||
|
||||
ifndef ANTLR4
|
||||
$(error variable ANTLR4 is not set)
|
||||
endif
|
||||
|
||||
default: $(PACKAGE)Parser.py
|
||||
|
||||
$(PACKAGE)Parser.py: $(PACKAGE).g4
|
||||
$(ANTLR4) $^ -Dlanguage=Python3
|
||||
|
||||
run: $(MAINFILE).py $(PACKAGE)Parser.py
|
||||
python3 $<
|
||||
|
||||
clean:
|
||||
rm -rf *~ $(PACKAGE)*.py $(PACKAGE)*.pyc *.interp *.tokens __pycache*
|
22
TP02/demo_files/ex3/main.py
Normal file
22
TP02/demo_files/ex3/main.py
Normal file
@ -0,0 +1,22 @@
|
||||
from antlr4 import InputStream
|
||||
from antlr4 import CommonTokenStream
|
||||
|
||||
# include to use the generated lexer and parser
|
||||
from Example3Lexer import Example3Lexer
|
||||
from Example3Parser import Example3Parser
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
input_stream = InputStream(sys.stdin.read())
|
||||
lexer = Example3Lexer(input_stream)
|
||||
stream = CommonTokenStream(lexer)
|
||||
parser = Example3Parser(stream)
|
||||
parser.full_expr()
|
||||
print("Finished")
|
||||
|
||||
|
||||
# warns pb if py file is included in others
|
||||
if __name__ == '__main__':
|
||||
main()
|
26
TP02/python/objects.py
Normal file
26
TP02/python/objects.py
Normal file
@ -0,0 +1,26 @@
|
||||
# Class without base class
|
||||
class Base():
|
||||
# Constructor (called by "Base()" when creating an object)
|
||||
def __init__(self):
|
||||
self.a = "set in Base's constructor"
|
||||
|
||||
def f(self):
|
||||
return self.a
|
||||
|
||||
def g(self):
|
||||
return "returned from Base's g()"
|
||||
|
||||
|
||||
class Derived(Base):
|
||||
# Function with the same name override the base class function.
|
||||
def f(self):
|
||||
return "returned from Derived's f()"
|
||||
|
||||
|
||||
b = Base() # Create an object of Base
|
||||
print(b.f()) # Method call, as usual OO languages
|
||||
print(b.g())
|
||||
|
||||
d = Derived()
|
||||
print(d.f())
|
||||
print(d.g())
|
53
TP02/python/type_unions.py
Normal file
53
TP02/python/type_unions.py
Normal file
@ -0,0 +1,53 @@
|
||||
from typing import List
|
||||
|
||||
# int | float means ``either an int or a float''.
|
||||
NUMBER = int | float # or Union[int, float] with Union imported from typing
|
||||
|
||||
|
||||
def add_numbers(a: NUMBER, b: NUMBER) -> NUMBER:
|
||||
return a + b
|
||||
|
||||
|
||||
# Both int and floats can be passed to the function
|
||||
print(add_numbers(1, 4.3))
|
||||
|
||||
|
||||
def divide_numbers(a: NUMBER, b: NUMBER) -> float:
|
||||
return a / b
|
||||
|
||||
|
||||
print(divide_numbers(1, 2))
|
||||
|
||||
# Declare the type of a list whose elements are numbers.
|
||||
LIST_OF_NUMBERS = List[NUMBER]
|
||||
|
||||
|
||||
def increment(a: LIST_OF_NUMBERS) -> LIST_OF_NUMBERS:
|
||||
return [x + 1 for x in a]
|
||||
|
||||
|
||||
print(increment([1, 2, 3]))
|
||||
|
||||
# Skip the end if you are late.
|
||||
|
||||
# The type DEEP_LIST_OF_NUMBERS is a special case since it references itself.
|
||||
# The identifier DEEP_LIST_OF_NUMBERS cannot be used before the end of its
|
||||
# initialization, but the circular dependency can be broken using the string
|
||||
# 'DEEP_LIST_OF_NUMBERS' instead.
|
||||
DEEP_LIST_OF_NUMBERS = NUMBER | List['DEEP_LIST_OF_NUMBERS']
|
||||
|
||||
|
||||
def deep_increment(d: DEEP_LIST_OF_NUMBERS) -> DEEP_LIST_OF_NUMBERS:
|
||||
if isinstance(d, list):
|
||||
# Note the unusual typing rule applied by Pyright here: because we are
|
||||
# in the 'isinstance(d, list)' branch, it knows that d is a list,
|
||||
# and accepts to iterate over it.
|
||||
return [deep_increment(e) for e in d]
|
||||
else:
|
||||
# ... and here, in the 'else' branch Pyright knows that d is
|
||||
# not a list,
|
||||
# and can deduce that it is a NUMBER.
|
||||
return d + 1
|
||||
|
||||
|
||||
print(deep_increment([1, [2, 3]]))
|
16
TP02/python/typecheck.py
Normal file
16
TP02/python/typecheck.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Typing annotations for variables:
|
||||
# name: type
|
||||
int_variable: int
|
||||
float_variable: float
|
||||
int_variable = 4.2 # Static typing error, but no runtime error
|
||||
float_variable = 42.0 # OK
|
||||
float_variable = int_variable # OK
|
||||
|
||||
|
||||
# Typing annotations for functions (-> means "returns")
|
||||
def int_to_string(i: int) -> str:
|
||||
return str(i)
|
||||
|
||||
|
||||
print(int_to_string('Hello')) # Static typing error, but no runtime error
|
||||
print(int_to_string(42) / 5) # Both static and runtime error
|
BIN
TP02/tp2.pdf
Normal file
BIN
TP02/tp2.pdf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user