file imports work!!!!!
This commit is contained in:
		
							
								
								
									
										35
									
								
								AST.py
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								AST.py
									
									
									
									
									
								
							| @@ -17,11 +17,13 @@ class NodeType(Enum): | ||||
|     BreakStatement = "BreakStatement" | ||||
|     ContinueStatement = "ContinueStatement" | ||||
|     ForStatement = "ForStatement" | ||||
|     DependStatement = "DependStatement" | ||||
|  | ||||
|     # Expressions | ||||
|     InfixExpression = "InfixExpression" | ||||
|     CallExpression = "CallExpression" | ||||
|     PrefixExpression = "PrefixExpression" | ||||
|     PostfixExpression = "PostfixExpression" | ||||
|  | ||||
|     # Literals | ||||
|     IntegerLiteral = "IntegerLiteral" | ||||
| @@ -295,7 +297,7 @@ class ContinueStatement(Statement): | ||||
|         } | ||||
|      | ||||
| class ForStatement(Statement): | ||||
|     def __init__(self, var_declaration: AssignmentStatement = None, condition: Expression = None, action: ReassignStatement = None, body: BlockStatement = None) -> None: | ||||
|     def __init__(self, var_declaration: AssignmentStatement = None, condition: Expression = None, action: Expression = None, body: BlockStatement = None) -> None: | ||||
|         self.var_declaration = var_declaration | ||||
|         self.condition = condition | ||||
|         self.action = action | ||||
| @@ -309,7 +311,21 @@ class ForStatement(Statement): | ||||
|             "type": self.type().value, | ||||
|             "var_declaration": self.var_declaration.json(), | ||||
|             "condition": self.condition.json(), | ||||
|             "body": self.body.json() | ||||
|             "body": self.body.json(), | ||||
|             "action": self.action.json() | ||||
|         } | ||||
|      | ||||
| class DependStatement(Statement): | ||||
|     def __init__(self, file_path: str) -> None: | ||||
|         self.file_path = file_path | ||||
|  | ||||
|     def type(self) -> NodeType: | ||||
|         return NodeType.DependStatement | ||||
|      | ||||
|     def json(self) -> dict: | ||||
|         return { | ||||
|             "type": self.type().value, | ||||
|             "file_path": self.file_path | ||||
|         } | ||||
| # endregion | ||||
|  | ||||
| @@ -360,4 +376,19 @@ class PrefixExpression(Expression): | ||||
|             "operator": self.operator, | ||||
|             "right_node": self.right_node.json() | ||||
|         } | ||||
|      | ||||
| class PostfixExpression(Expression): | ||||
|     def __init__(self, left_node: IdentifierLiteral, operator: str) -> None: | ||||
|         self.left_node = left_node | ||||
|         self.operator = operator | ||||
|  | ||||
|     def type(self) -> NodeType: | ||||
|         return NodeType.PostfixExpression | ||||
|      | ||||
|     def json(self) -> dict: | ||||
|         return { | ||||
|             "type": self.type().value, | ||||
|             "left_node": self.left_node.json(), | ||||
|             "operator": self.operator | ||||
|         } | ||||
| # endregion | ||||
							
								
								
									
										64
									
								
								compiler.py
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								compiler.py
									
									
									
									
									
								
							| @@ -1,14 +1,18 @@ | ||||
| from llvmlite import ir | ||||
| import os | ||||
|  | ||||
| from AST import Node, NodeType, Program, Expression | ||||
| from AST import ExpressionStatement, AssignmentStatement, BlockStatement, ReturnStatement, FunctionStatement, ReassignStatement, IfStatement | ||||
| from AST import WhileStatement, BreakStatement, ContinueStatement, ForStatement | ||||
| from AST import InfixExpression, CallExpression, PrefixExpression | ||||
| from AST import WhileStatement, BreakStatement, ContinueStatement, ForStatement, DependStatement | ||||
| from AST import InfixExpression, CallExpression, PrefixExpression, PostfixExpression | ||||
| from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral, BooleanLiteral, StringLiteral | ||||
| from AST import FunctionParameter | ||||
|  | ||||
| from environment import Environment | ||||
|  | ||||
| from lexer import Lexer | ||||
| from plasma_parser import Parser | ||||
|  | ||||
|  | ||||
| class Compiler: | ||||
| 	def __init__(self) -> None: | ||||
| @@ -36,6 +40,8 @@ class Compiler: | ||||
| 		self.breakpoints: list[ir.Block] = [] | ||||
| 		self.continues: list[ir.Block] = [] | ||||
|  | ||||
| 		self.global_parsed_pallets: dict[str, Program] = {} | ||||
|  | ||||
| 	def __initialize_builtins(self) -> None: | ||||
| 		def __init_print() -> ir.Function: | ||||
| 			fnty: ir.FunctionType = ir.FunctionType( | ||||
| @@ -96,12 +102,16 @@ class Compiler: | ||||
| 				self.__visit_continue_statement(node) | ||||
| 			case NodeType.ForStatement: | ||||
| 				self.__visit_for_statement(node) | ||||
| 			case NodeType.DependStatement: | ||||
| 				self.__visit_depend_statement(node) | ||||
|  | ||||
| 			# Expressions | ||||
| 			case NodeType.InfixExpression: | ||||
| 				self.__visit_infix_expression(node) | ||||
| 			case NodeType.CallExpression: | ||||
| 				self.__visit_call_expression(node) | ||||
| 			case NodeType.PostfixExpression: | ||||
| 				self.__visit_postfix_expression(node) | ||||
|  | ||||
| 	# region Visit Methods | ||||
| 	def __visit_program(self, node: Program) -> None: | ||||
| @@ -326,6 +336,30 @@ class Compiler: | ||||
|  | ||||
| 		self.breakpoints.pop() | ||||
| 		self.continues.pop() | ||||
|  | ||||
| 	def __visit_depend_statement(self, node: DependStatement) -> None: | ||||
| 		file_path: str = node.file_path | ||||
|  | ||||
| 		if self.global_parsed_pallets.get(file_path) is not None: | ||||
| 			print(f"warning: \"{file_path}\" is already imported globally!\n") | ||||
| 			return | ||||
| 		 | ||||
| 		with open(os.path.abspath(file_path), "r") as f: | ||||
| 			pallet_code: str = f.read() | ||||
|  | ||||
| 		l: Lexer = Lexer(pallet_code) | ||||
| 		p: Parser = Parser(l) | ||||
|  | ||||
| 		program: Program = p.parse_program() | ||||
| 		if len(p.errors) > 0: | ||||
| 			print(f"Error in dependency: {file_path}") | ||||
| 			for err in p.errors: | ||||
| 				print(err) | ||||
| 			exit(1) | ||||
|  | ||||
| 		self.compile(program) | ||||
|  | ||||
| 		self.global_parsed_pallets[file_path] = program | ||||
| 	# endregion	 | ||||
|  | ||||
| 	# region Expressions | ||||
| @@ -455,6 +489,32 @@ class Compiler: | ||||
| 					value = self.builder.not_(right_value) | ||||
|  | ||||
| 		return value, Type | ||||
| 	 | ||||
| 	def __visit_postfix_expression(self, node: PostfixExpression) -> None: | ||||
| 		left_node: IdentifierLiteral = node.left_node | ||||
| 		operator: str = node.operator | ||||
|  | ||||
| 		if self.environment.lookup(left_node.value) is None: | ||||
| 			self.errors.append(f"Identifier {left_node.value} has not been declared before it was re-assigned.") | ||||
| 			return | ||||
| 		 | ||||
| 		var_ptr, _ = self.environment.lookup(left_node.value) | ||||
| 		orig_value = self.builder.load(var_ptr) | ||||
|  | ||||
| 		value = None | ||||
| 		match operator: | ||||
| 			case "++": | ||||
| 				if isinstance(orig_value.type, ir.IntType): | ||||
| 					value = self.builder.add(orig_value, ir.Constant(ir.IntType(32), 1)) | ||||
| 				elif isinstance(orig_value.type, ir.FloatType): | ||||
| 					value = self.builder.fadd(orig_value, ir.Constant(ir.FloatType(), 1.0)) | ||||
| 			case "--": | ||||
| 				if isinstance(orig_value.type, ir.IntType): | ||||
| 					value = self.builder.sub(orig_value, ir.Constant(ir.IntType(32), 1)) | ||||
| 				elif isinstance(orig_value.type, ir.FloatType): | ||||
| 					value = self.builder.fsub(orig_value, ir.Constant(ir.FloatType(), 1.0)) | ||||
|  | ||||
| 		self.builder.store(value, var_ptr) | ||||
| 	# endregion | ||||
|  | ||||
| 	# endregion | ||||
|   | ||||
							
								
								
									
										47
									
								
								debug/ast.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								debug/ast.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| { | ||||
|     "type": "Program", | ||||
|     "statements": [ | ||||
|         { | ||||
|             "DependStatement": { | ||||
|                 "type": "DependStatement", | ||||
|                 "file_path": "tests/math.pla" | ||||
|             } | ||||
|         }, | ||||
|         { | ||||
|             "FunctionStatement": { | ||||
|                 "type": "FunctionStatement", | ||||
|                 "name": { | ||||
|                     "type": "IdentifierLiteral", | ||||
|                     "value": "main" | ||||
|                 }, | ||||
|                 "return_type": "Int", | ||||
|                 "parameters": [], | ||||
|                 "body": { | ||||
|                     "type": "BlockStatement", | ||||
|                     "statements": [ | ||||
|                         { | ||||
|                             "type": "ReturnStatement", | ||||
|                             "return_value": { | ||||
|                                 "type": "CallExpression", | ||||
|                                 "function": { | ||||
|                                     "type": "IdentifierLiteral", | ||||
|                                     "value": "add" | ||||
|                                 }, | ||||
|                                 "arguments": [ | ||||
|                                     { | ||||
|                                         "type": "IntegerLiteral", | ||||
|                                         "value": 1 | ||||
|                                     }, | ||||
|                                     { | ||||
|                                         "type": "IntegerLiteral", | ||||
|                                         "value": 2 | ||||
|                                     } | ||||
|                                 ] | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										13
									
								
								debug/ir.ll
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								debug/ir.ll
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| ; ModuleID = "main" | ||||
| target triple = "x86_64-unknown-linux-gnu" | ||||
| target datalayout = "" | ||||
|  | ||||
| declare i32 @"printf"(i8* %".1", ...) | ||||
|  | ||||
| @"true" = constant i1 1 | ||||
| @"false" = constant i1 0 | ||||
| define i32 @"main"() | ||||
| { | ||||
| main_entry: | ||||
|   ret i32 0 | ||||
| } | ||||
							
								
								
									
										8
									
								
								lexer.py
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								lexer.py
									
									
									
									
									
								
							| @@ -88,6 +88,10 @@ class Lexer: | ||||
| 					ch = self.current_char | ||||
| 					self.__read_char() | ||||
| 					tok = self.__new_token(TokenType.PLUS_EQ, ch + self.current_char) | ||||
| 				elif self.__peek_char() == "+": | ||||
| 					ch = self.current_char | ||||
| 					self.__read_char() | ||||
| 					tok = self.__new_token(TokenType.PLUS_PLUS, ch + self.current_char) | ||||
| 				else: | ||||
| 					tok = self.__new_token(TokenType.PLUS, self.current_char) | ||||
| 			case "-": | ||||
| @@ -95,6 +99,10 @@ class Lexer: | ||||
| 					ch = self.current_char | ||||
| 					self.__read_char() | ||||
| 					tok = self.__new_token(TokenType.MINUS_EQ, ch + self.current_char) | ||||
| 				elif self.__peek_char() == "-": | ||||
| 					ch = self.current_char | ||||
| 					self.__read_char() | ||||
| 					tok = self.__new_token(TokenType.MINUS_MINUS, ch + self.current_char) | ||||
| 				else: | ||||
| 					tok = self.__new_token(TokenType.MINUS, self.current_char) | ||||
| 			case "*": | ||||
|   | ||||
| @@ -47,8 +47,14 @@ class TokenType(Enum): | ||||
| 	SEMICOLON = "SEMICOLON" | ||||
| 	COMMA = "COMMA" | ||||
| 	DOLLARSIGN = "DOLLARSIGN" | ||||
|  | ||||
| 	# Prefix symbols | ||||
| 	BANG = "BANG" | ||||
|  | ||||
| 	# Postfix symbols | ||||
| 	PLUS_PLUS = "PLUS_PLUS" | ||||
| 	MINUS_MINUS = "MINUS_MINUS" | ||||
|  | ||||
| 	# Keywords | ||||
| 	RETURN = "RETURN" | ||||
| 	IF = "IF" | ||||
| @@ -59,6 +65,7 @@ class TokenType(Enum): | ||||
| 	CONTINUE = "CONTINUE" | ||||
| 	BREAK = "BREAK" | ||||
| 	FOR = "FOR" | ||||
| 	DEPEND = "DEPEND" | ||||
|  | ||||
| 	# Typing | ||||
| 	TYPE = "TYPE" | ||||
| @@ -86,12 +93,12 @@ KEYWORDS: dict[str, TokenType] = { | ||||
| 	"while": TokenType.WHILE, | ||||
| 	"break": TokenType.BREAK, | ||||
| 	"continue": TokenType.CONTINUE, | ||||
| 	"for": TokenType.FOR | ||||
| 	"for": TokenType.FOR, | ||||
| 	"depend": TokenType.DEPEND | ||||
| } | ||||
|  | ||||
| ALT_KEYWORDS: dict[str, TokenType] = { | ||||
| 	"else": TokenType.UNLESS, | ||||
| 	"ret": TokenType.RETURN | ||||
|  | ||||
| } | ||||
|  | ||||
| TYPE_KEYWORDS: list[str] = ["Int", "Float", "String", "Bool", "List", "Nil", "Func"] | ||||
|   | ||||
							
								
								
									
										2
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.py
									
									
									
									
									
								
							| @@ -10,7 +10,7 @@ import llvmlite.binding as llvm | ||||
| from ctypes import CFUNCTYPE, c_int, c_float | ||||
|  | ||||
| LEXER_DEBUG: bool = False | ||||
| PARSER_DEBUG: bool = True | ||||
| PARSER_DEBUG: bool = False | ||||
| COMPILER_DEBUG: bool = False | ||||
| RUN_CODE: bool = True | ||||
|  | ||||
|   | ||||
| @@ -5,8 +5,8 @@ from enum import Enum, auto | ||||
|  | ||||
| from AST import Statement, Expression, Program | ||||
| from AST import ExpressionStatement, AssignmentStatement, FunctionStatement, ReturnStatement, BlockStatement, ReassignStatement, IfStatement, WhileStatement | ||||
| from AST import InfixExpression, CallExpression, PrefixExpression | ||||
| from AST import BreakStatement, ContinueStatement, ForStatement | ||||
| from AST import InfixExpression, CallExpression, PrefixExpression, PostfixExpression | ||||
| from AST import BreakStatement, ContinueStatement, ForStatement, DependStatement | ||||
| from AST import IntegerLiteral, FloatLiteral, IdentifierLiteral, BooleanLiteral, StringLiteral | ||||
| from AST import FunctionParameter | ||||
|  | ||||
| @@ -34,7 +34,10 @@ PRECEDENCES: dict[TokenType, PrecedenceType] = { | ||||
| 	TokenType.GT: PrecedenceType.P_LESSGREATER, | ||||
| 	TokenType.LT_EQ: PrecedenceType.P_LESSGREATER, | ||||
| 	TokenType.GT_EQ: PrecedenceType.P_LESSGREATER, | ||||
| 	TokenType.DOLLARSIGN: PrecedenceType.P_CALL | ||||
| 	TokenType.DOLLARSIGN: PrecedenceType.P_CALL, | ||||
|  | ||||
| 	TokenType.PLUS_PLUS: PrecedenceType.P_INDEX, | ||||
| 	TokenType.MINUS_MINUS: PrecedenceType.P_INDEX | ||||
| } | ||||
|  | ||||
| class Parser: | ||||
| @@ -76,6 +79,10 @@ class Parser: | ||||
| 			TokenType.GT: self.__parse_infix_expression, | ||||
| 			TokenType.LT_EQ: self.__parse_infix_expression, | ||||
| 			TokenType.GT_EQ: self.__parse_infix_expression, | ||||
|  | ||||
|  | ||||
| 			TokenType.PLUS_PLUS: self.__parse_postfix_expression, | ||||
| 			TokenType.MINUS_MINUS: self.__parse_postfix_expression | ||||
| 			 | ||||
| 		}  | ||||
|  | ||||
| @@ -158,6 +165,8 @@ class Parser: | ||||
| 				return self.__parse_continue_statement() | ||||
| 			case TokenType.FOR: | ||||
| 				return self.__parse_for_statement() | ||||
| 			case TokenType.DEPEND: | ||||
| 				return self.__parse_depend_statement() | ||||
| 			case _: | ||||
| 				return self.__parse_expression_statement() | ||||
|  | ||||
| @@ -372,9 +381,7 @@ class Parser: | ||||
| 		 | ||||
| 		self.__next_token() # skip ; | ||||
| 		 | ||||
| 		stmt.action = self.__parse_assignment_statement() | ||||
|  | ||||
| 		 | ||||
| 		stmt.action = self.__parse_expression(PrecedenceType.P_LOWEST) | ||||
|  | ||||
| 		self.__next_token() | ||||
|  | ||||
| @@ -384,6 +391,17 @@ class Parser: | ||||
| 		stmt.body = self.__parse_block_statement() | ||||
|  | ||||
| 		return stmt | ||||
| 	 | ||||
| 	def __parse_depend_statement(self) -> DependStatement: | ||||
| 		if not self.__expect_peek(TokenType.STRING): | ||||
| 			return None | ||||
| 		 | ||||
| 		stmt: DependStatement = DependStatement(self.current_token.literal) | ||||
|  | ||||
| 		if not self.__expect_peek(TokenType.SEMICOLON): | ||||
| 			return None | ||||
| 		 | ||||
| 		return stmt | ||||
| 	# endregion | ||||
|  | ||||
| 	# region Expression Methods | ||||
| @@ -393,9 +411,9 @@ class Parser: | ||||
| 			self.__no_prefix_parse_function_error(self.current_token.type) | ||||
| 			return None | ||||
| 		 | ||||
| 		 | ||||
| 		left_expr: Expression = prefix_func() | ||||
| 		while not self.__peek_token_is(TokenType.SEMICOLON) and precedence.value < self.__peek_precedence().value: | ||||
| 			 | ||||
| 			infix_func: Callable | None = self.infix_parse_functions.get(self.peek_token.type) | ||||
| 			if infix_func is None: | ||||
| 				return left_expr | ||||
| @@ -403,6 +421,7 @@ class Parser: | ||||
| 			self.__next_token() | ||||
|  | ||||
| 			left_expr = infix_func(left_expr) | ||||
| 			 | ||||
| 		 | ||||
| 		return left_expr | ||||
|  | ||||
| @@ -457,6 +476,9 @@ class Parser: | ||||
| 		prefix_expr.right_node = self.__parse_expression(PrecedenceType.P_PREFIX) | ||||
|  | ||||
| 		return prefix_expr | ||||
| 	 | ||||
| 	def __parse_postfix_expression(self, left_node: Expression) -> PostfixExpression: | ||||
| 		return PostfixExpression(left_node, self.current_token.literal) | ||||
| 	# endregion | ||||
|  | ||||
| 	# region Prefix Methods | ||||
|   | ||||
| @@ -1,9 +0,0 @@ | ||||
| depend "io.pla" | ||||
|  | ||||
| if 1 + 2 == 3 { | ||||
| 	print("The universe is functional!"); | ||||
| } | ||||
| unless | ||||
| { | ||||
| 	print("WHAT, HOW"); | ||||
| } | ||||
| @@ -1,8 +0,0 @@ | ||||
| depend "io.pla" | ||||
| depend "string.pla" | ||||
|  | ||||
| add = Func(a: Int, b: Int): Int { | ||||
| 	return a + b; | ||||
| } | ||||
|  | ||||
| print(String(add(1, 3))); | ||||
| @@ -1,4 +1,4 @@ | ||||
| main = Func(): Int { | ||||
| 	$print("Hello, World!"); | ||||
| 	$print("Hello, World!\n"); | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										3
									
								
								tests/math.pla
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								tests/math.pla
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| add = Func(a: Int, b: Int): Int { | ||||
| 	return a + b; | ||||
| } | ||||
| @@ -1,7 +1,5 @@ | ||||
| depend "tests/math.pla"; | ||||
|  | ||||
| main = Func(): Int { | ||||
| 	a: Int = 10; | ||||
|  | ||||
| 	a += 1; | ||||
|  | ||||
| 	return a; | ||||
| 	return $add(1 ,2); | ||||
| } | ||||
| @@ -1,19 +0,0 @@ | ||||
| depend "io.pla" | ||||
|  | ||||
| enum Gender { | ||||
| 	male, | ||||
| 	female | ||||
| } | ||||
|  | ||||
| struct Person { | ||||
| 	name: String, | ||||
| 	age: Int = 0, | ||||
| 	speak: Func, | ||||
| 	gender: Gender | ||||
| } | ||||
|  | ||||
| speak = Func(sentence: String): Nil { | ||||
| 	print(sentence) | ||||
| } | ||||
|  | ||||
| max: Person = {"Max", 17, speak, Gender.male}; | ||||
| @@ -1,16 +0,0 @@ | ||||
| depend "string.pla" | ||||
| depend "io.h" | ||||
|  | ||||
| myInt: Int = 123; | ||||
| myDecimal: Float = 0.456; | ||||
| myBoolean: Bool = true; | ||||
| myString: String = "Hello!\n"; | ||||
| myList: List = [1, "hi", true, [1, 2, 3], 0.789]; | ||||
|  | ||||
| MY_CONSTANT: Const(String) = "foo bar"; | ||||
|  | ||||
| print(String(myInt)); | ||||
| print(String(myDecimal)); | ||||
| print(String(myBoolean)); | ||||
| print(myString); | ||||
| print(String(myList)); | ||||
		Reference in New Issue
	
	Block a user
	 SpookyDervish
					SpookyDervish