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