mirror of
https://github.com/Ed94/LangStudies.git
synced 2024-11-10 04:14:53 -08:00
467 lines
10 KiB
GDScript
467 lines
10 KiB
GDScript
extends Object
|
|
|
|
# ---------------------------------------------------------- UTILITIES
|
|
var ErrorOut
|
|
|
|
func check( condition : bool, message : String):
|
|
assert(condition, message)
|
|
if ! condition:
|
|
ErrorOut.text = "Eva - Error: " + message
|
|
|
|
func throw( message ):
|
|
assert(false, message)
|
|
ErrorOut.text = "Eva - Error: " + message
|
|
# ---------------------------------------------------------- UTILITIES END
|
|
|
|
class_name Parser
|
|
|
|
# ---------------------------------------------------------- AST Node
|
|
|
|
const NType = \
|
|
{
|
|
program = "Program",
|
|
|
|
empty = "Empty",
|
|
|
|
block = "Scope Block",
|
|
|
|
conditional = "Conditional",
|
|
expr_Switch = "Expression Switch",
|
|
expr_While = "Expression While",
|
|
expr_For = "Expression For",
|
|
|
|
literal_Number = "Literal: Number",
|
|
literal_String = "Literal: String",
|
|
|
|
op_Assign = "Assignment",
|
|
op_Fn = "Function Call",
|
|
|
|
op_Add = "+",
|
|
op_Sub = "-",
|
|
op_Mult = "*",
|
|
op_Div = "/",
|
|
op_Increment = "++",
|
|
op_Decrement = "--",
|
|
|
|
op_Greater = ">",
|
|
op_GreaterEqual = ">=",
|
|
op_Lesser = "<",
|
|
op_LesserEqual = "<=",
|
|
op_Equal = "=",
|
|
op_NotEqual = "!=",
|
|
|
|
fn_Print = "Print",
|
|
fn_User = "User Function",
|
|
fn_Lambda = "Lambda Function",
|
|
fn_IIL = "Lambda Function Immediate Invocation",
|
|
fn_Params = "Function Parameters",
|
|
fn_Body = "Function Body",
|
|
|
|
identifier = "Identifier",
|
|
variable = "Variable"
|
|
}
|
|
|
|
class ASTNode:
|
|
var Data : Array
|
|
|
|
func get_class() :
|
|
return "ASTNode"
|
|
|
|
func add_Expr( expr ):
|
|
Data.append(expr)
|
|
|
|
func add_TokenValue( token ):
|
|
Data.append( token.Value )
|
|
|
|
func set_Type( nType ):
|
|
Data.append(nType)
|
|
|
|
func arg( id ):
|
|
return Data[id]
|
|
|
|
func num_args():
|
|
return Data.size() - 1
|
|
|
|
func type():
|
|
return Data[0]
|
|
|
|
func is_op_Relation():
|
|
match type():
|
|
NType.op_Greater: return true
|
|
NType.op_Lesser: return true
|
|
NType.op_GreaterEqual: return true
|
|
NType.op_LesserEqual: return true
|
|
NType.op_Equal: return true
|
|
NType.op_NotEqual: return true
|
|
_: return false
|
|
|
|
func is_op_Numeric():
|
|
match type():
|
|
NType.op_Add: return true
|
|
NType.op_Sub: return true
|
|
NType.op_Mult: return true
|
|
NType.op_Div: return true
|
|
NType.op_Increment: return true
|
|
NType.op_Decrement: return true
|
|
_: return false
|
|
|
|
func is_Number():
|
|
return type() == NType.literal_Number
|
|
|
|
func is_String():
|
|
return type() == NType.literal_String
|
|
|
|
func string():
|
|
return arg(1).substr(1, arg(1).length() -2)
|
|
|
|
# Serialization ----------------------------------------------------
|
|
func array_Serialize(array, fn_objSerializer) :
|
|
var result = []
|
|
|
|
for entry in array :
|
|
if typeof(entry) == TYPE_ARRAY :
|
|
result.append( array_Serialize( entry, fn_objSerializer ))
|
|
|
|
elif typeof(entry) == TYPE_OBJECT :
|
|
if entry.get_class() == "Eva":
|
|
result.append(entry)
|
|
else:
|
|
fn_objSerializer.set_instance(entry)
|
|
result.append( fn_objSerializer.call_func() )
|
|
|
|
else :
|
|
result.append( entry )
|
|
|
|
return result
|
|
|
|
func to_SExpression():
|
|
var \
|
|
to_SExpression_Fn = FuncRef.new()
|
|
to_SExpression_Fn.set_function("to_SExpression")
|
|
|
|
return array_Serialize( self.Data, to_SExpression_Fn )
|
|
# Serialization END -------------------------------------------------
|
|
|
|
# ---------------------------------------------------------- AST Node END
|
|
|
|
const SLexer = preload("Lexer.gd")
|
|
const TType = SLexer.TType
|
|
var Lexer : SLexer
|
|
|
|
var NextToken : SLexer.Token
|
|
|
|
# Gets the next token only if the current token is the specified intended token (tokenType)
|
|
func eat(tokenType):
|
|
var currToken = NextToken
|
|
|
|
check(currToken != null, "Parser - eat: NextToken was null")
|
|
|
|
var assertStrTmplt = "Parser - eat: Unexpected token: {value}, expected: {type}"
|
|
var assertStr = assertStrTmplt.format({"value" : currToken.Value, "type" : tokenType})
|
|
|
|
check(currToken.Type == tokenType, assertStr)
|
|
|
|
NextToken = Lexer.next_Token()
|
|
|
|
return currToken
|
|
|
|
func parse():
|
|
var \
|
|
node = ASTNode.new()
|
|
node.set_Type(NType.program)
|
|
|
|
while NextToken != null :
|
|
if NextToken.Type == TType.def_Start:
|
|
node.add_Expr( parse_Expression() )
|
|
|
|
elif NextToken.Type == TType.identifier:
|
|
node.add_Expr( parse_Identifier() )
|
|
|
|
elif NextToken.is_Literal():
|
|
node.add_Expr( parse_Literal() )
|
|
|
|
return node
|
|
|
|
func parse_Expression():
|
|
eat(TType.def_Start)
|
|
var node : ASTNode
|
|
|
|
match NextToken.Type :
|
|
TType.def_Block:
|
|
node = parse_Simple(TType.def_Block, NType.block)
|
|
TType.def_Cond:
|
|
node = parse_Simple(TType.def_cond, NType.conditional)
|
|
TType.def_Switch:
|
|
node = parse_Switch()
|
|
TType.def_While:
|
|
node = parse_Simple(TType.def_While, NType.expr_While)
|
|
TType.def_For:
|
|
node = parse_Simple(TType.def_For, NType.expr_For)
|
|
TType.def_Var:
|
|
node = parse_Variable()
|
|
TType.def_Func:
|
|
node = parse_fn_User()
|
|
TType.def_Lambda:
|
|
node = parse_fn_Lambda()
|
|
TType.fn_Print:
|
|
node = parse_Simple(TType.fn_Print, NType.fn_Print)
|
|
TType.op_Assgin:
|
|
node = parse_op_Assign()
|
|
TType.op_Numeric:
|
|
node = parse_op_Numeric()
|
|
TType.op_Relational:
|
|
node = parse_op_Relational()
|
|
TType.op_Equality:
|
|
node = ASTNode.new()
|
|
match NextToken.Value:
|
|
NType.op_Equal:
|
|
node.set_Type(NType.op_Equal)
|
|
NType.op_NotEqual:
|
|
node.set_Type(NType.op_NotEqual)
|
|
eat(TType.op_Equality)
|
|
TType.identifier:
|
|
node = parse_op_Fn()
|
|
TType.def_Start:
|
|
node = parse_fn_IIL()
|
|
|
|
while NextToken.Type != TType.def_End:
|
|
if NextToken.Type == TType.def_Start:
|
|
node.add_Expr( parse_Expression() )
|
|
elif NextToken.Type == TType.identifier:
|
|
node.add_Expr( parse_Identifier() )
|
|
else :
|
|
node.add_Expr( parse_Literal() )
|
|
|
|
eat(TType.def_End)
|
|
|
|
if node == null:
|
|
node = ASTNode.new()
|
|
node.set_Type(NType.empty)
|
|
|
|
return node
|
|
|
|
func parse_Simple(tType, nType):
|
|
var \
|
|
node = ASTNode.new()
|
|
node.set_Type(nType)
|
|
eat(tType)
|
|
|
|
return node
|
|
|
|
func parse_Switch():
|
|
var \
|
|
node = ASTNode.new()
|
|
node.set_Type(NType.expr_Switch)
|
|
eat(TType.def_Switch)
|
|
|
|
return node
|
|
|
|
func parse_Variable():
|
|
var \
|
|
node = ASTNode.new()
|
|
node.set_Type(NType.variable)
|
|
eat(TType.def_Var)
|
|
|
|
check( NextToken.Type == TType.identifier,
|
|
String("Parser - parse_Variable: NextToken should have been identifier. TokenData - Type: {type} Value: {value}") \
|
|
.format({"type" : NextToken.Type, "value" : NextToken.Value })
|
|
)
|
|
|
|
node.add_TokenValue( NextToken )
|
|
eat(TType.identifier)
|
|
|
|
return node
|
|
|
|
func parse_fn_User():
|
|
var \
|
|
node = ASTNode.new()
|
|
node.set_Type(NType.fn_User)
|
|
eat(TType.def_Func)
|
|
|
|
check( NextToken.Type == TType.identifier,
|
|
String("Parser - parse_op_Assign: NextToken should have been identifier, Type: {type} Value: {value}") \
|
|
.format({"type" : NextToken.Type, "value" : NextToken.Value })
|
|
)
|
|
|
|
node.add_TokenValue( NextToken )
|
|
eat(TType.identifier)
|
|
|
|
# Parameters
|
|
var \
|
|
pNode = ASTNode.new()
|
|
pNode.set_Type(NType.fn_Params)
|
|
eat(TType.def_Start)
|
|
|
|
while NextToken.Type != TType.def_End:
|
|
check( NextToken.Type == TType.identifier,
|
|
String("Parser - parse_op_Assign: NextToken should have been identifier, Type: {type} Value: {value}") \
|
|
.format({"type" : NextToken.Type, "value" : NextToken.Value })
|
|
)
|
|
|
|
pNode.add_TokenValue(NextToken)
|
|
eat(TType.identifier)
|
|
|
|
eat(TType.def_End)
|
|
|
|
var \
|
|
bNode = ASTNode.new()
|
|
bNode.set_Type(NType.fn_Body)
|
|
|
|
while NextToken.Type != TType.def_End:
|
|
bNode.add_Expr( parse_Expression() )
|
|
|
|
node.add_Expr( pNode )
|
|
node.add_Expr( bNode )
|
|
|
|
return node
|
|
|
|
func parse_fn_Lambda():
|
|
var \
|
|
node = ASTNode.new()
|
|
node.set_Type(NType.fn_Lambda)
|
|
eat(TType.def_Lambda)
|
|
|
|
# Parameters
|
|
var \
|
|
pNode = ASTNode.new()
|
|
pNode.set_Type(NType.fn_Params)
|
|
eat(TType.def_Start)
|
|
|
|
while NextToken.Type != TType.def_End:
|
|
check( NextToken.Type == TType.identifier,
|
|
String("Parser - parse_op_Assign: NextToken should have been identifier, Type: {type} Value: {value}") \
|
|
.format({"type" : NextToken.Type, "value" : NextToken.Value })
|
|
)
|
|
|
|
pNode.add_TokenValue(NextToken)
|
|
eat(TType.identifier)
|
|
|
|
eat(TType.def_End)
|
|
|
|
var \
|
|
bNode = ASTNode.new()
|
|
bNode.set_Type(NType.fn_Body)
|
|
|
|
while NextToken.Type != TType.def_End:
|
|
bNode.add_Expr( parse_Expression() )
|
|
|
|
node.add_Expr( pNode )
|
|
node.add_Expr( bNode )
|
|
|
|
return node
|
|
|
|
func parse_fn_IIL():
|
|
var \
|
|
node = ASTNode.new()
|
|
node.set_Type(NType.fn_IIL)
|
|
|
|
# Lambda
|
|
node.add_Expr( parse_Expression() )
|
|
|
|
return node
|
|
|
|
func parse_Identifier():
|
|
var \
|
|
node = ASTNode.new()
|
|
node.set_Type(NType.identifier)
|
|
node.add_TokenValue(NextToken)
|
|
|
|
eat(TType.identifier)
|
|
|
|
return node
|
|
|
|
func parse_op_Assign():
|
|
var \
|
|
node = ASTNode.new()
|
|
node.set_Type(NType.op_Assign)
|
|
|
|
eat(TType.op_Assgin)
|
|
|
|
check( NextToken.Type == TType.identifier,
|
|
String("Parser - parse_op_Assign: NextToken should have been identifier, Type: {type} Value: {value}") \
|
|
.format({"type" : NextToken.Type, "value" : NextToken.Value })
|
|
)
|
|
|
|
node.add_TokenValue( NextToken )
|
|
eat(TType.identifier)
|
|
|
|
if NextToken.is_Literal() :
|
|
node.add_Expr( parse_Literal() )
|
|
|
|
elif NextToken.Type == TType.def_Start :
|
|
node.add_Expr( parse_Expression() )
|
|
|
|
return node
|
|
|
|
func parse_op_Numeric():
|
|
var node = ASTNode.new()
|
|
|
|
match NextToken.Value:
|
|
NType.op_Add:
|
|
node.set_Type(NType.op_Add)
|
|
NType.op_Sub:
|
|
node.set_Type(NType.op_Sub)
|
|
NType.op_Mult:
|
|
node.set_Type(NType.op_Mult)
|
|
NType.op_Div:
|
|
node.set_Type(NType.op_Div)
|
|
NType.op_Increment:
|
|
node.set_Type(NType.op_Increment)
|
|
NType.op_Decrement:
|
|
node.set_Type(NType.op_Decrement)
|
|
|
|
eat(TType.op_Numeric)
|
|
|
|
return node
|
|
|
|
func parse_op_Relational():
|
|
var node = ASTNode.new()
|
|
|
|
match NextToken.Value:
|
|
NType.op_Greater:
|
|
node.set_Type(NType.op_Greater)
|
|
NType.op_Lesser:
|
|
node.set_Type(NType.op_Lesser)
|
|
NType.op_GreaterEqual:
|
|
node.set_Type(NType.op_GreaterEqual)
|
|
NType.op_LesserEqual:
|
|
node.set_Type(NType.op_LesserEqual)
|
|
|
|
eat(TType.op_Relational)
|
|
|
|
return node
|
|
|
|
func parse_op_Fn():
|
|
var \
|
|
node = ASTNode.new()
|
|
node.set_Type(NType.op_Fn)
|
|
node.add_TokenValue( NextToken )
|
|
eat(TType.identifier)
|
|
|
|
return node
|
|
|
|
func parse_Literal():
|
|
var node = ASTNode.new()
|
|
|
|
match NextToken.Type:
|
|
TType.literal_Number:
|
|
node.set_Type(NType.literal_Number)
|
|
node.add_TokenValue(NextToken)
|
|
|
|
eat(TType.literal_Number)
|
|
|
|
TType.literal_String:
|
|
node.set_Type(NType.literal_String)
|
|
node.add_TokenValue(NextToken)
|
|
|
|
eat(TType.literal_String)
|
|
|
|
return node
|
|
|
|
func _init(lexer, errorOut) :
|
|
ErrorOut = errorOut
|
|
Lexer = lexer
|
|
|
|
NextToken = Lexer.next_Token()
|
|
|