156 lines
No EOL
4.7 KiB
Python
156 lines
No EOL
4.7 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import tokenizer
|
|
import parser
|
|
import sys
|
|
import collections
|
|
|
|
# path = sys.argv[1]
|
|
path = 'a.scm'
|
|
|
|
f = open(path, 'r')
|
|
file_content = "".join(f.readlines())
|
|
|
|
tokenized_content = tokenizer.tokenize(file_content)
|
|
|
|
parser = parser.Parser()
|
|
|
|
raw_ast = parser.parse(tokenized_content)
|
|
|
|
'''
|
|
Type inferencing
|
|
'''
|
|
ASTItemToken = collections.namedtuple('Node', ['content', 'type','free_var'])
|
|
|
|
def generate_empty_ast_token(ls):
|
|
kind = ""
|
|
free_var = []
|
|
if isinstance(ls,list):
|
|
content = [generate_empty_ast_token(i) for i in ls]
|
|
return ASTItemToken(content=content, type=kind, free_var=free_var)
|
|
else:
|
|
return ASTItemToken(content=ls, type=kind, free_var=free_var)
|
|
|
|
to_check_if_double_defined_ast = generate_empty_ast_token(raw_ast)
|
|
|
|
'''
|
|
data type list (Non-Closure or void):
|
|
[
|
|
(Type_name, Parent_Type, Detail)
|
|
Parent_type: if it's not subtype, the value is None.
|
|
Detail: Type detail of type [record or union] ["record", {"a": "int", "b": "dou"}] or None
|
|
|
|
]
|
|
'''
|
|
type_ls = [
|
|
("p_int","int",None),
|
|
("n_int", "int", None),
|
|
("z_int", "int", None),
|
|
("int", None, None),
|
|
("dou", None, None),
|
|
("str", None, None),
|
|
]
|
|
|
|
'''
|
|
var_and_type_list
|
|
'''
|
|
var_and_type_list = [
|
|
("%+", ("case", [
|
|
("->", ("p_int", "p_int"), "p_int"),
|
|
("->", ("n_int", "n_int"), "n_int"),
|
|
("->", ("p_int", "n_int"), "int"),
|
|
("->", ("n_int", "p_int"), "int"),
|
|
("->", ("int", "int"), "int"),
|
|
("->", ("dou", "dou"), "dou")
|
|
])
|
|
)
|
|
]
|
|
|
|
vars_ls = [{'defined' : {'%+', '%p'}, 'used' : {}}]
|
|
|
|
'''
|
|
check if there are any double defined variable
|
|
'''
|
|
def find_if_double_defined(ast, vars_ls):
|
|
if isinstance(ast.content,list):
|
|
for item in ast:
|
|
vars_ls = find_if_double_defined_aux(item, vars_ls)
|
|
return vars_ls
|
|
else:
|
|
return find_if_double_defined_aux(ast, vars_ls)
|
|
|
|
def find_if_double_defined_aux(ast, vars_ls):
|
|
if isinstance(ast.content,list):
|
|
ast_head = ast.content[0]
|
|
|
|
# define variable
|
|
if ast_head.val == 'define':
|
|
var_name = ast.content[1].val
|
|
current_variable_frame = vars_ls[-1]
|
|
if var_name in current_variable_frame['defined'] or var_name in current_variable_frame['used']:
|
|
raise Exception("variable double defined at ln %d, col %d" % (ast_head.line, ast_head.column))
|
|
else:
|
|
vars_ls[-1]['defined'].add(var_name) # add the new-defined to the list
|
|
rhs_var_ls = find_if_double_defined_aux(ast.content[3], vars_ls)
|
|
return vars_ls
|
|
|
|
# lambda
|
|
if ast_head.val == 'lambda':
|
|
orig_vars_ls = vars_ls
|
|
extended_vars_ls = vars_ls + [{'defined' : {}, 'used' : {}}]
|
|
# (lambda ((y int) ...)
|
|
if isinstance(ast.content[1].content, list):
|
|
arg_list = map(lambda x : x.content[0], ast.content[1].content)
|
|
# lambda (y ...)
|
|
else:
|
|
arg_list = map(lambda x : x.content, ast.content[1].content)
|
|
|
|
for arg in arg_list:
|
|
arg_name = arg.val
|
|
line = arg.line
|
|
column = arg.column
|
|
|
|
if arg_name in extended_vars_ls[-1]['defined']:
|
|
raise Exception("variable double defined at ln %d, col %d" % (line, column))
|
|
else:
|
|
extended_vars_ls[-1]['defined'].add(arg_name)
|
|
|
|
# after adding arguments, visit lambda body
|
|
for item in ast.content[2:]:
|
|
extended_vars_ls = find_if_double_defined_aux(item, extended_vars_ls)
|
|
|
|
# return orig_vars_ls, don't pollute it.
|
|
return orig_vars_ls
|
|
|
|
# function applying or basic operator, visiting all items
|
|
else:
|
|
for item in ast.content:
|
|
vars_ls = find_if_double_defined_aux(item, vars_ls)
|
|
return vars_ls
|
|
|
|
# variable or constant
|
|
else:
|
|
if ast.type in ['SYMBOL', 'OP']:
|
|
vars_ls[-1]['used'].add(arg_name)
|
|
else:
|
|
pass
|
|
|
|
return vars_ls
|
|
|
|
to_be_typeinferenced_ast = find_if_double_defined(to_check_if_double_defined_ast, vars_ls)
|
|
|
|
|
|
'''
|
|
TODO: 型別推測
|
|
|
|
def typeinfer(ast, type_ls, var_type_ls):
|
|
if isinstance(ast.content,list):
|
|
return [typeinfer_aux(ast, type_ls, var_type_ls) for i in ast]
|
|
else:
|
|
return typeinfer_aux(ast, type_ls, var_type_ls)
|
|
|
|
def typeinfer_aux(ast, type_ls, var):
|
|
if isinstance(ast.content, list):
|
|
list_head = ast.content[0]
|
|
if list_head.content.val == 'define':
|
|
''' |