288 lines
11 KiB
Plaintext
288 lines
11 KiB
Plaintext
|
import "ppp_tokens.ppp";
|
||
|
import "ppp_lexer.ppp";
|
||
|
import "ppp_ast.ppp";
|
||
|
import "ppp_parser.ppp";
|
||
|
import "ppp_types.ppp";
|
||
|
import "ppp_object.ppp";
|
||
|
import "ppp_stdlib.ppp";
|
||
|
|
||
|
enum VariableState {
|
||
|
Declared(Type, Object),
|
||
|
Undeclared(Type),
|
||
|
Constant(Type, Object)
|
||
|
}
|
||
|
|
||
|
func declared_from_obj(obj: Object) -> VariableState return VariableState.Declared(object_get_type(obj), obj);
|
||
|
|
||
|
type Module = dict[str, VariableState];
|
||
|
|
||
|
struct Program {
|
||
|
modules: dict[str, Module],
|
||
|
contexts: dict[str, VariableState][]
|
||
|
}
|
||
|
|
||
|
func program_exists(program: Program, name: str) -> bool {
|
||
|
for context in program.contexts do {
|
||
|
for name_ in context do {
|
||
|
if name_ == name return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
func program_access_variable(program: Program, name: str) -> Object {
|
||
|
i: int = len(program.contexts) - 1;
|
||
|
while i >= 0 do {
|
||
|
context: dict[str, VariableState] = program.contexts[i];
|
||
|
for name_ in context do {
|
||
|
if name_ == name do {
|
||
|
value: VariableState = context[name];
|
||
|
match value in {
|
||
|
case Declared(_, value) return value;
|
||
|
case Const(_, value) return value;
|
||
|
case Undeclared(_) assert false, "'%s' is not defined!" % name;
|
||
|
case _ assert false, "Unimplemented program_access_variable %s" % value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
i = i - 1;
|
||
|
}
|
||
|
assert false, "'%s' is not defined!" % name;
|
||
|
}
|
||
|
|
||
|
func program_declare_variable(program: Program, name: str, type_: Type) {
|
||
|
for name_ in program.contexts[len(program.contexts)-1] assert name_ != name, "'%s' has already been declared!" % name;
|
||
|
program.contexts[len(program.contexts)-1][name] = VariableState.Undeclared(type_);
|
||
|
}
|
||
|
|
||
|
func program_assign_variable(program: Program, name: str, value: Object) {
|
||
|
i: int = len(program.contexts) - 1;
|
||
|
while i >= 0 do {
|
||
|
context: dict[str, VariableState] = program.contexts[i];
|
||
|
for name_ in context do {
|
||
|
if name_ == name do {
|
||
|
variable_type: Type;
|
||
|
match context[name] in {
|
||
|
case Undeclared(type_) variable_type = type_;
|
||
|
case _ assert false, "Unimplemented program_assign_variable %s" % context[name];
|
||
|
}
|
||
|
assert type_is_subtype_of(object_get_type(value), variable_type), "In the assignment of '%s', expected value of type '%s', but got a value of type '%s'!" % (name, type_represent(variable_type, type_represent(object_get_type(value))));
|
||
|
context[name] = VariableState.Declared(variable_type, value);
|
||
|
return none;
|
||
|
}
|
||
|
}
|
||
|
i = i - 1;
|
||
|
}
|
||
|
assert false, "'%s' doesn't exist!" % name;
|
||
|
}
|
||
|
|
||
|
func program_declare_and_assign_variable(program: Program, name: str, value: Object) {
|
||
|
program_declare_variable(program, name, object_get_type(value));
|
||
|
program_assign_variable(program, name, value);
|
||
|
}
|
||
|
|
||
|
func calculate_expression(expression: Expression, program: Program) -> Object {
|
||
|
match expression in {
|
||
|
case String(string) return Object.Str(string);
|
||
|
case Array(array_) do {
|
||
|
if len(array_) == 0 return Object.List(Type.List(Type.Variable("")), []);
|
||
|
elements_type: Type;
|
||
|
array_elements: Object[] = [];
|
||
|
for i in range(0, len(array_)) do {
|
||
|
element: Object = calculate_expression(array_[i], program);
|
||
|
if i == 0 elements_type = object_get_type(element);
|
||
|
else assert type_is_subtype_of(object_get_type(element), elements_type), "Array element invalid type";
|
||
|
array_elements = array_elements + [element];
|
||
|
}
|
||
|
assert false, "array %s" % array_elements;
|
||
|
}
|
||
|
case Dictionary(dict_) do {
|
||
|
if len(dict_) == 0 return Object.Dictionary(Type.Dictionary(Type.Variable(""), Type.Variable("")), {});
|
||
|
key_type: Type;
|
||
|
value_type: Type;
|
||
|
dict: dict[Object, Object] = {};
|
||
|
for i in range(0, len(dict_)) do {
|
||
|
key: Object = calculate_expression(dict_[i][0], program);
|
||
|
value: Object = calculate_expression(dict_[i][1], program);
|
||
|
if i == 0 do {
|
||
|
key_type = object_get_type(key);
|
||
|
value_type = object_get_type(value);
|
||
|
} else {
|
||
|
assert type_is_subtype_of(object_get_type(key), key_type), "Dict element invalid key type";
|
||
|
assert type_is_subtype_of(object_get_type(value), value_type), "Dict element invalid value type";
|
||
|
}
|
||
|
dict[key] = value;
|
||
|
}
|
||
|
assert false, "dict %s" % dict;
|
||
|
}
|
||
|
case FieldAccess(expression_, field) do {
|
||
|
value: Object = calculate_expression(expression_, program);
|
||
|
match value in {
|
||
|
case Type(type_) match type_ in {
|
||
|
case Enum(name, members, _) do {
|
||
|
for member in members do {
|
||
|
if member == field do {
|
||
|
if len(members[field]) == 0 return Object.EnumValue(type_, field, []);
|
||
|
func return_member(name: str, parameters: (str, Type)[], return_type: Type, statement: Statement, args: Object[]) -> Object {
|
||
|
match return_type in {
|
||
|
case Enum(_, _, _) do {}
|
||
|
case _ assert false, "Unreachable";
|
||
|
}
|
||
|
|
||
|
assert len(args) == len(parameters), "%s.%s expected %s arguments but got %s!" % (type_represent(type_), field, int_to_str(len(parameters)), int_to_str(len(args)));
|
||
|
for i in range(0, len(args)) assert type_is_subtype_of(object_get_type(args[i]), parameters[i][1]);
|
||
|
return Object.EnumValue(return_type, name, args);
|
||
|
}
|
||
|
return Object.Function(Type.Function(members[field], type_), (field, [("", member_type) for member_type in members[field]], type_, Statement.Statements([]), return_member));
|
||
|
}
|
||
|
}
|
||
|
assert false, "g";
|
||
|
}
|
||
|
case _ assert false, "Unimplemented calculate_expression field access type %s" % type_represent(type_);
|
||
|
}
|
||
|
case _ assert false, "Unimplemented calculate_expression field access %s" % value;
|
||
|
}
|
||
|
}
|
||
|
case Variable(name) return program_access_variable(program, name);
|
||
|
case _ assert false, "Unimplemented calculate_expression %s" % expression;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func calculate_type_expression(expression: TypeExpression, program: Program, must_resolve: bool) -> Type {
|
||
|
match expression in {
|
||
|
case Name(name) do {
|
||
|
if !program_exists(program, name) && !must_resolve return Type.Variable(name);
|
||
|
type_obj: Object = program_access_variable(program, name);
|
||
|
match type_obj in {
|
||
|
case Type(type_) return type_;
|
||
|
case _ assert false, "Unimplemented %s" % type_obj;
|
||
|
}
|
||
|
}
|
||
|
case List(type_) return Type.List(calculate_type_expression(type_, program, must_resolve));
|
||
|
case Tuple(types) return Type.Tuple([calculate_type_expression(type_, program, must_resolve) for type_ in types]);
|
||
|
case _ assert false, "Unimplemented calculate_type_expression %s" % expression;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func update_types(type_: Type, program: Program) {
|
||
|
type_name: str;
|
||
|
match type_ in {
|
||
|
case Enum(name, _, _) type_name = name;
|
||
|
case Struct(name, _, _) type_name = name;
|
||
|
|
||
|
case _ assert false, "Unimplemented update_types %s" % type_represent(type_);
|
||
|
}
|
||
|
for context in program.contexts do {
|
||
|
for variable_ in context do {
|
||
|
match context[variable_] in {
|
||
|
case Declared(variable_type, value) match value in {
|
||
|
case Type(variable_type_) do {
|
||
|
assert variable_type == Type.Type;
|
||
|
type_fill(variable_type_, {type_name: type_}, []);
|
||
|
}
|
||
|
}
|
||
|
case Undeclared(_) do {}
|
||
|
case _ assert false, "Unimplemented update_types %s" % context[variable_];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
enum Result {
|
||
|
Return(Object),
|
||
|
Continue,
|
||
|
Break,
|
||
|
Nothing
|
||
|
}
|
||
|
|
||
|
func interpret_statements(statements: Statement[], program: Program) -> Result {
|
||
|
for statement in statements do {
|
||
|
match statement in {
|
||
|
case Import(file_) do {
|
||
|
file_path: Object = calculate_expression(file_, program);
|
||
|
match file_path in {
|
||
|
case Str(file_path_str) do {
|
||
|
found: bool = false;
|
||
|
module: Module;
|
||
|
for module_ in program.modules do {
|
||
|
if module_ == file_path_str do {
|
||
|
found = true;
|
||
|
module = program.modules[module_];
|
||
|
}
|
||
|
}
|
||
|
if !found do {
|
||
|
print("Importing %s\n" % file_path_str);
|
||
|
module = interpret_file(file_path_str, program.modules);
|
||
|
}
|
||
|
|
||
|
for variable in module do program.contexts[0][variable] = module[variable];
|
||
|
|
||
|
if !found program.modules[file_path_str] = module;
|
||
|
}
|
||
|
case _ assert false, "Unimplemented interpret_statement import %s" % file_path;
|
||
|
}
|
||
|
}
|
||
|
case EnumDefinition(name, entries) do {
|
||
|
enum_type: Type = Type.Enum(name, {entry.name: [calculate_type_expression(type_, program, false) for type_ in entry.types] for entry in entries}, []);
|
||
|
program_declare_and_assign_variable(program, name, Object.Type(enum_type));
|
||
|
update_types(enum_type, program);
|
||
|
}
|
||
|
case FunctionDefinition(name, arguments_, return_type_, body) do {
|
||
|
func run_function(name: str, arguments: (str, Type)[], return_type: Type, body: Statement, args: Object[]) -> Object {
|
||
|
assert false, "run_function";
|
||
|
}
|
||
|
|
||
|
arguments: (str, Type)[] = [(argument.name, calculate_type_expression(argument.type_, program, true)) for argument in arguments_];
|
||
|
return_type: Type;
|
||
|
match return_type_ in {
|
||
|
case Some(type_) return_type = calculate_type_expression(type_, program, true);
|
||
|
case None return_type = Type.Void;
|
||
|
}
|
||
|
function_type: Type = Type.Function([argument[1] for argument in arguments], return_type);
|
||
|
object: Object = Object.Function(function_type, (name, arguments, return_type, body, run_function));
|
||
|
program_declare_and_assign_variable(program, name, object);
|
||
|
}
|
||
|
case StructDefinition(name, entries) do {
|
||
|
struct_type: Type = Type.Struct(name, {entry.name: calculate_type_expression(entry.type_, program, false) for entry in entries}, []);
|
||
|
program_declare_and_assign_variable(program, name, Object.Type(struct_type));
|
||
|
update_types(struct_type, program);
|
||
|
}
|
||
|
case Assignment(lhs, rhs, type_) do {
|
||
|
assert is_valid_target(lhs);
|
||
|
match lhs in {
|
||
|
case Variable(name) do {
|
||
|
value: Object = calculate_expression(rhs, program);
|
||
|
match type_ in {
|
||
|
case _ assert false, "uuuu %s" % type_;
|
||
|
}
|
||
|
}
|
||
|
case _ assert false, "Unimplemented interpret_statement assignment %s" % lhs;
|
||
|
}
|
||
|
}
|
||
|
case _ assert false, "Unimplemented interpret_statement %s" % statement;
|
||
|
}
|
||
|
}
|
||
|
return Result.Nothing;
|
||
|
}
|
||
|
|
||
|
|
||
|
func interpret_file(file_path: str, modules: dict[str, Module]) -> Module {
|
||
|
print("Parsing %s...\n" % file_path);
|
||
|
lexer: Lexer = lexer_from_file(file_path);
|
||
|
statements: Statement[] = [];
|
||
|
while !is_some_token(lexer_take_token(lexer, TokenContents.Eof)) statements = statements + [parse_statement(lexer)];
|
||
|
new_variables: dict[str, VariableState] = {};
|
||
|
for variable in variables new_variables[variable] = declared_from_obj(variables[variable]);
|
||
|
program: Program = Program{modules=modules, contexts=[new_variables, {}]};
|
||
|
print("Interpreting %s...\n" % file_path);
|
||
|
return_value: Result = interpret_statements(statements, program);
|
||
|
assert len(program.contexts) == 2;
|
||
|
match return_value in {
|
||
|
case Nothing do {}
|
||
|
case Return(_) assert false, "Cannot return from outside a function!";
|
||
|
case Continue assert false, "Cannot continue from outside a loop!";
|
||
|
case Break assert false, "Cannot break from outside a loop!";
|
||
|
case _ assert false, "Unimplemented interpret_file return_value";
|
||
|
}
|
||
|
return program.contexts[1];
|
||
|
}
|