LangStudies/App/RDP/Scripts/RDP_Parser.gd

1074 lines
23 KiB
GDScript3
Raw Normal View History

2022-07-14 14:12:25 -07:00
extends Object
2022-07-23 23:56:37 -07:00
class_name RDP_Parser
2022-07-14 14:12:25 -07:00
const NodeType = \
{
program = "Program",
expr_Assignment = "Assignment Expression",
expr_Call = "Call Expression",
expr_ClassExtend = "Class Extension",
expr_Binary = "Binary Expression",
expr_Logical = "Logical Expression",
expr_Member = "Member Expression",
expr_New = "New Expression",
expr_Super = "Super Expression",
expr_This = "This Expression",
expr_Unary = "Unary Expression",
def_Class = "Class Declaration",
def_Procedure = "Function Declaration",
def_Variable = "Variable Declaration",
literal_Bool = "Boolean Literal",
literal_Numeric = "Numeric Literal",
literal_String = "String Literal",
literal_Null = "Null Literal",
stmt_Block = "Block Statement",
stmt_Conditional = "Conditional Statement",
stmt_Expression = "Expression Statement",
stmt_Empty = "Empty Statement",
stmt_Variable = "Variable Statement",
stmt_While = "While Statement",
stmt_DoWhile = "Do-While Statement",
stmt_For = "For Statement",
stmt_Return = "Return Statement",
sym_Identifier = "Identifier"
}
class PNode:
var Type : String
var Value # Not specifing a type implicity declares a Variant type.
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 :
fn_objSerializer.set_instance(entry)
result.append( fn_objSerializer.call_func() )
else :
result.append( entry )
return result
func to_SExpression():
var expression = [ Type ]
if typeof(Value) == TYPE_ARRAY :
var \
to_SExpression_Fn = FuncRef.new()
to_SExpression_Fn.set_function("to_SExpression")
var array = array_Serialize( self.Value, to_SExpression_Fn )
expression.append(array)
return expression
if typeof(Value) == TYPE_OBJECT :
var result = [ Type, Value.to_SExpression() ]
return result
expression.append(Value)
return expression
func to_Dictionary():
if typeof(Value) == TYPE_ARRAY :
var \
to_Dictionary_Fn = FuncRef.new()
to_Dictionary_Fn.set_function("to_Dictionary")
var array = array_Serialize( self.Value, to_Dictionary_Fn )
var result = \
{
Type = self.Type,
Value = array
}
return result
if typeof(Value) == TYPE_OBJECT :
var result = \
{
Type = self.Type,
Value = self.Value.to_Dictionary()
}
return result
var result = \
{
Type = self.Type,
Value = self.Value
}
return result
2022-07-23 23:56:37 -07:00
var SLexer : Script = preload("res://RDP/Scripts/RDP_Lexer.gd")
2022-07-14 14:12:25 -07:00
var TokenType = SLexer.TokenType
2022-07-23 23:56:37 -07:00
var NextToken : RDP_Lexer.Token
2022-07-14 14:12:25 -07:00
var Lexer
# --------------------------------------------------------------------- HELPERS
# Gets the next token only if the current token is the specified intended token (tokenType)
func eat(tokenType):
var currToken = NextToken
assert(currToken != null, "eat: NextToken was null")
var assertStrTmplt = "eat: Unexpected token: {value}, expected: {type}"
var assertStr = assertStrTmplt.format({"value" : currToken.Value, "type" : tokenType})
assert(currToken.Type == tokenType, assertStr)
NextToken = Lexer.next_Token()
return currToken
func is_Literal():
return \
NextToken.Type == TokenType.literal_Number \
|| NextToken.Type == TokenType.literal_String \
|| NextToken.Type == TokenType.literal_BTrue \
|| NextToken.Type == TokenType.literal_BFalse \
|| NextToken.Type == TokenType.literal_Null
# BinaryExpression
# : MultiplicativeExpression
# | AdditiveExpression
# ;
func parse_BinaryExpression(parse_fn, operatorToken):
var left = parse_fn.call_func()
while NextToken.Type == operatorToken:
var operator = eat(operatorToken)
var right = parse_fn.call_func()
var \
nestedNode = PNode.new()
nestedNode.Type = NodeType.expr_Binary
nestedNode.Value = []
nestedNode.Value.append(operator.Value)
nestedNode.Value.append(left)
nestedNode.Value.append(right)
left = nestedNode;
return left
# LogicalExpression
# : LogicalAndExpression
# | LogicalOrExpression
# ;
func parse_LogicalExpression(parse_fn, operatorToken):
var left = parse_fn.call_func()
while NextToken.Type == operatorToken :
var operator = eat(operatorToken).Value
var right = parse_fn.call_func()
var \
nestedNode = PNode.new()
nestedNode.Type = NodeType.expr_Logical
nestedNode.Value = []
nestedNode.Value.append(operator)
nestedNode.Value.append(left)
nestedNode.Value.append(right)
left = nestedNode
return left
# ------------------------------------------------------------------ END HELPERS
# Parses the text program description into an AST.
func parse(lexer):
Lexer = lexer
NextToken = lexer.next_Token()
return parse_Program()
# > parse
# Program
# : StatementList
# : Literal
# ;
func parse_Program():
var \
node = PNode.new()
node.Type = NodeType.program
node.Value = parse_StatementList(null)
if node.Value == [ null ] :
print("WTF")
return node
# > Program
# > BlockStatement
# StatementList
# : Statement
# | StatementList Statement -> Statement ...
# ;
func parse_StatementList(endToken):
var statementList = [ parse_Statement() ]
while NextToken != null && NextToken.Type != endToken :
statementList.append( parse_Statement() )
return statementList
# > StatementList
# > If_Statement
# > WhileStatement
# Statement
# : ExpressionStatement
# | BlockStatement
# | EmptyStatement
# | VariableStatement
# | If_Statement
# | IterationStatement
# | FunctionDeclaration
# | ReturnStatement
# | ClassDeclaration
# ;
func parse_Statement():
if NextToken == null :
return null
match NextToken.Type :
TokenType.def_If :
return parse_If_Statement()
TokenType.def_End :
return parse_EmptyStatement()
TokenType.def_BStart :
return parse_BlockStatement()
TokenType.def_Var :
return parse_VariableStatement()
TokenType.def_While :
return parse_IterationStatement()
TokenType.def_Do :
return parse_IterationStatement()
TokenType.def_For :
return parse_IterationStatement()
TokenType.def_Proc:
return parse_FunctionDeclaration()
TokenType.def_Return:
return parse_ReturnStatement()
TokenType.def_Class:
return parse_ClassDeclaration()
return parse_ExpressionStatement()
# If Statement
# : if ( Expression ) Statement
# | if ( Expression ) Statement else Statement
# ;
func parse_If_Statement():
eat(TokenType.def_If)
eat(TokenType.expr_PStart)
var condition = parse_Expression()
eat(TokenType.expr_PEnd)
var consequent = parse_Statement()
var alternative = null
if NextToken != null && NextToken.Type == TokenType.def_Else :
eat(TokenType.def_Else)
alternative = parse_Statement()
var \
node = PNode.new()
node.Type = NodeType.stmt_Conditional
node.Value = [ condition, consequent, alternative ]
return node
# > Statement
# EmptyStatement
# ;
func parse_EmptyStatement():
eat(TokenType.def_End)
var \
node = PNode.new()
node.Type = NodeType.stmt_Empty
return node
# > Statement
# BlockStatement
# : { OptStatementList }
# ;
func parse_BlockStatement():
eat(TokenType.def_BStart)
var \
node = PNode.new()
node.Type = NodeType.stmt_Block
if NextToken.Type != TokenType.def_BEnd :
node.Value = parse_StatementList(TokenType.def_BEnd)
else :
node.Value = []
eat(TokenType.def_BEnd)
return node
# > Statement
# VariableStatement
# : VariableStatementInit StatementEnd
# ;
func parse_VariableStatement():
var varStatement = parse_VariableStatementInit()
eat(TokenType.def_End)
return varStatement
# > VariableStatement
# VariableStatementInit
# : VarDeclare VariableDeclarationList
# ;
func parse_VariableStatementInit():
eat(TokenType.def_Var)
var declarations = parse_VariableDeclarationList()
var \
node = PNode.new()
node.Type = NodeType.stmt_Variable
node.Value = declarations
return node
# > Statement
# IterationStatement
# : WhileStatement
# | DoWhileStatement
# | ForStatement
# ;
func parse_IterationStatement():
match NextToken.Type:
TokenType.def_While :
return parse_WhileStatement()
TokenType.def_Do :
return parse_DoWhileStatement()
TokenType.def_For :
return parse_ForStatement()
# > IterationStatement
# WhileStatement
# : while ( Expression ) Statement
# ;
func parse_WhileStatement():
eat(TokenType.def_While)
eat(TokenType.expr_PStart)
var condition = parse_Expression()
eat(TokenType.expr_PEnd)
var body = parse_Statement()
var \
node = PNode.new()
node.Type = NodeType.stmt_While
node.Value = [ condition, body ]
return node
# > IterationStatement
# DoWhileStatement
# : do Statement while ( Expression )
# ;
func parse_DoWhileStatement():
eat(TokenType.def_Do)
var body = parse_Statement()
eat(TokenType.def_While)
eat(TokenType.expr_PStart)
var condition = parse_Expression()
eat(TokenType.expr_PEnd)
eat(TokenType.def_End)
var \
node = PNode.new()
node.Type = NodeType.stmt_DoWhile
node.Value = [ condition, body ]
return node
# > IterationStatement
# ForStatement
# : for (
# OptForStatementInit ;
# OptExpression ;
# OptExpression
# )
# Statement
# ;
func parse_ForStatement():
eat(TokenType.def_For)
eat(TokenType.expr_PStart)
var init = null
var condition = null
var update = null
if NextToken.Type != TokenType.def_End :
init = parse_ForStatementInit()
eat(TokenType.def_End)
if NextToken.Type != TokenType.def_End :
condition = parse_Expression()
eat(TokenType.def_End)
if NextToken.Type != TokenType.expr_PEnd :
update = parse_Expression()
eat(TokenType.expr_PEnd)
var body = parse_Statement()
var \
node = PNode.new()
node.Type = NodeType.stmt_For
node.Value = [ init, condition, update, body ]
return node
# > ForStatement
# ForStatementInit
# : VariableStatemetnInit
# | Expression
# ;
func parse_ForStatementInit():
if NextToken.Type == TokenType.def_Var :
return parse_VariableStatementInit()
return parse_Expression()
# > Statement
# FunctionDeclaration
# : FuncDeclare ( OptFomralParameterList ) BlockStatement
# ;
func parse_FunctionDeclaration():
eat(TokenType.def_Proc)
var name = parse_Identifier()
eat(TokenType.expr_PStart)
var params
if NextToken.Type != TokenType.expr_PEnd :
params = parse_FormalParameterList()
else :
params = []
eat(TokenType.expr_PEnd)
var body = parse_BlockStatement()
var \
node = PNode.new()
node.Type = NodeType.def_Procedure
node.Value = [ name, params, body ]
return node
# > FunctionDeclaration
# FormalParameterList
# : Identifier
# | FormalParameterList , Identifier
# ;
func parse_FormalParameterList():
var params = [ parse_Identifier() ]
while NextToken.Type == TokenType.delim_Comma :
eat(TokenType.delim_Comma)
params.append(parse_Identifier())
return params
# > Statement
# ReturnStatement
# : return OptExpression
# ;
func parse_ReturnStatement():
eat(TokenType.def_Return)
var argument = null
if NextToken.Type != TokenType.def_End :
argument = parse_Expression()
eat(TokenType.def_End)
var \
node = PNode.new()
node.Type = NodeType.stmt_Return
node.Value = argument
return node
# > Statement
# ClassDeclaration
# : class Identifier OptClassExtends BLockStatement
# ;
func parse_ClassDeclaration():
eat(TokenType.def_Class)
var identifier = parse_Identifier()
var superClass = null
if NextToken.Type == TokenType.expr_Extends :
superClass = parse_ClassExtension()
var body = parse_BlockStatement()
var \
node = PNode.new()
node.Type = NodeType.def_Class
node.Value = [ identifier, superClass, body ]
return node
# > ClassDeclaration
# ClassExtension
# : extends Identifier
# ;
func parse_ClassExtension():
eat(TokenType.expr_Extends)
return parse_Identifier()
# > Statement
# ExpressionStatement
# : Expression
# ;
func parse_ExpressionStatement():
var expression = parse_Expression()
eat(TokenType.def_End)
var \
node = PNode.new()
node.Type = NodeType.stmt_Expression
node.Value = expression
return expression
# > ExpressionStatement
# > If_Statement
# > WhileStatement
# > PrimaryExpression
# Expression
# : AssignmentExpression
# ;
func parse_Expression():
return parse_AssignmentExpression()
# > VariableStatement
# VariableDeclarationList
# : VariableDeclaration
# | VariableDelcarationList , VariableDeclaration -> VariableDelcaration , ...
func parse_VariableDeclarationList():
var \
declarations = []
declarations.append(parse_VariableDeclaration())
while NextToken.Type == TokenType.delim_Comma :
eat(TokenType.delim_Comma)
declarations.append(parse_VariableDeclaration())
return declarations
# > VariableDeclarationList
# VariableDeclaration
# : Identifier OptVariableInitalizer
# ;
func parse_VariableDeclaration():
var identifier = parse_Identifier()
var initalizer
if NextToken.Type != TokenType.def_End \
&& NextToken.Type != TokenType.delim_Comma :
initalizer = parse_VariableInitializer()
else :
initalizer = null
var \
node = PNode.new()
node.Type = NodeType.def_Variable
node.Value = [ identifier, initalizer ]
return node
# > VariableDeclaration
# VariableInitializer
# : Assignment AssignmentExpression
# ;
func parse_VariableInitializer():
eat(TokenType.op_Assign)
return parse_AssignmentExpression()
# > Expression
# > VariableInitializer
# > AssignmentExpression
# AssignmentExpression
# : RelationalExpression
# | ResolvedSymbol AssignmentOperator AssignmetnExpression
# ;
func parse_AssignmentExpression():
var left = parse_LogicalOrExpression()
if NextToken.Type != TokenType.op_Assign \
&& NextToken.Type != TokenType.op_CAssign :
return left
var assignmentOp;
if NextToken.Type == TokenType.op_Assign :
assignmentOp = eat(TokenType.op_Assign)
elif NextToken.Type == TokenType.op_CAssign :
assignmentOp = eat(TokenType.op_CAssign)
var \
node = PNode.new()
node.Type = NodeType.expr_Assignment
node.Value = \
[
assignmentOp.Value,
left,
parse_AssignmentExpression()
]
return node
# > VariableDeclaration
# > ParenthesizedExpression
# Identifier
# : IdentifierSymbol
# ;
func parse_Identifier():
var name = eat(TokenType.sym_Identifier).Value
var \
node = PNode.new()
node.Type = NodeType.sym_Identifier
node.Value = name
return node
# > AssignmentExpression
# Logical Or Expression
# : LogicalAndExpression Logical_Or LogicalOrExpression
# | LogicalOrExpression
# ;
func parse_LogicalOrExpression():
var \
parseFn = FuncRef.new()
parseFn.set_instance(self)
parseFn.set_function("pasre_LogicalAndExpression")
return parse_LogicalExpression(parseFn, TokenType.op_LOr)
# > LogicaOrExpression
# Logical And Expression
# : EqualityExpression Logical_And LogicalAndExpression
# | EqualityExpression
# ;
func pasre_LogicalAndExpression():
var \
parseFn = FuncRef.new()
parseFn.set_instance(self)
parseFn.set_function("parse_EqualityExpression")
return parse_LogicalExpression(parseFn, TokenType.op_LAnd)
# Equality Operators: ==, !=
#
# > LogicalAndExpression
# EqualityExpression
# : RelationalExpression EqualityOp RelationalExpression
# | RelationalExpression
# ;
func parse_EqualityExpression():
var \
parseFn = FuncRef.new()
parseFn.set_instance(self)
parseFn.set_function("parse_RelationalExpression")
return parse_BinaryExpression(parseFn, TokenType.op_Equality)
# Relational Operators: >, >=, <, <=
#
# > EqualityExpression
# Relational Expression
# : AdditiveExpression
# | AdditiveExpression RelationalOp RelationalExpression
# ;
func parse_RelationalExpression():
var \
parseFn = FuncRef.new()
parseFn.set_instance(self)
parseFn.set_function("parse_AdditiveExpression")
return parse_BinaryExpression(parseFn, TokenType.op_Relational)
# > RelationalExpression
# AdditiveExpression
# : MultiplicativeExpression
# | AdditiveExpression AdditiveOp MultiplicativeExpression -> MultiplicativeExpression AdditiveOp ... Literal
# ;
func parse_AdditiveExpression():
var \
parseFn = FuncRef.new()
parseFn.set_instance(self)
parseFn.set_function("parse_MultiplicativeExpression")
return parse_BinaryExpression(parseFn, TokenType.op_Additive)
# > AdditiveExpression
# MultiplicativeExpression
# : UnaryExpressioon
# : MultiplicativeExpression MultiplicativeOp UnaryExpression -> UnaryExpression MultiplicativeOp ... Literal
# ;
func parse_MultiplicativeExpression():
var \
parseFn = FuncRef.new()
parseFn.set_instance(self)
parseFn.set_function("parse_UnaryExpression")
return parse_BinaryExpression(parseFn, TokenType.op_Multiplicative)
# > MultiplicativeExpression
# > UnaryExpression
# UnaryExpression
# : ResolvedSymbol
# | AdditiveOp UnaryExpression
# | Logical_Not UnaryExpression
# ;
func parse_UnaryExpression():
var operator
match NextToken.Type:
TokenType.op_Additive:
operator = eat(TokenType.op_Additive).Value
TokenType.op_LNot:
operator = eat(TokenType.op_LNot).Value
if operator == null :
return parse_ResolvedSymbol()
var \
node = PNode.new()
node.Type = NodeType.expr_Unary
node.Value = [ operator, parse_UnaryExpression() ]
return node;
# > UnaryExpression
# > PrimaryExpression
# ResolvedSymbol (LeftHandExpression)
# : MemberExpression
# ;
func parse_ResolvedSymbol():
return parse_FunctionExpression()
# > ResolvedSymbol
# FunctionExpression
# : Super
# | MemberExpression
# | CallExpression
# ;
func parse_FunctionExpression():
if NextToken.Type == TokenType.expr_Super :
return parse_CallExpression(parse_SuperExpression())
var member = parse_MemberExpression()
if NextToken.Type == TokenType.expr_PStart :
return parse_CallExpression(member)
return member
# > FunctionExpression
# Super
# : super
# ;
func parse_SuperExpression():
eat(TokenType.expr_Super)
var \
node = PNode.new()
node.Type = NodeType.expr_Super
return node
# > ResolvedSymbol
# MemberExpression
# : PrimaryExpression
# | MemberExpression . Identifier
# | MemberExpression [ Expression ]
# ;
func parse_MemberExpression():
var expression = parse_PrimaryExpression()
while NextToken.Type == TokenType.delim_SMR || NextToken.Type == TokenType.expr_SBStart :
if NextToken.Type == TokenType.delim_SMR :
eat(TokenType.delim_SMR)
var member = parse_Identifier()
var \
node = PNode.new()
node.Type = NodeType.expr_Member
node.Value = [ false, expression, member ]
expression = node
if NextToken.Type == TokenType.expr_SBStart :
eat(TokenType.expr_SBStart)
var sbExpression = parse_Expression()
eat(TokenType.expr_SBEnd)
var \
node = PNode.new()
node.Type = NodeType.expr_Member
node.Value = [ true, expression, sbExpression ]
expression = node
return expression
# > FunctionExpression
# CallExpression
# : Callee Arguments
# ;
#
# Callee
# : MemberExpression
# | CallExpression
# ;
func parse_CallExpression(callee):
var \
callExpression = PNode.new()
callExpression.Type = NodeType.expr_Call
callExpression.Value = \
[
callee,
parse_Arguments()
]
if NextToken.Type == TokenType.expr_PStart :
callExpression = parse_CallExpression(callExpression)
return callExpression
# > CallExpression
# Arugments
# : ( OptArgumentList )
# ;
func parse_Arguments():
eat(TokenType.expr_PStart)
var argumentList = null
if NextToken.Type != TokenType.expr_PEnd :
argumentList = parse_ArgumentList()
eat(TokenType.expr_PEnd)
return argumentList
# > Arguments
# ArgumentList
# : AssignmentExpression
# | ArgumentList , AssignmentExpression
# ;
func parse_ArgumentList():
var argumentList = [ parse_AssignmentExpression() ]
while NextToken.Type == TokenType.delim_Comma :
eat(TokenType.delim_Comma)
argumentList.append( parse_AssignmentExpression() )
return argumentList
# > MemberExpression
# PrimaryExpression
# : Literal
# | ParenthesizedExpression
# | Identifier
# | ThisExpression
# | NewExpression
# ;
func parse_PrimaryExpression():
if is_Literal():
return parse_Literal()
match NextToken.Type:
TokenType.expr_PStart:
return parse_ParenthesizedExpression()
TokenType.sym_Identifier:
var identifier = parse_Identifier()
if identifier.Type == NodeType.sym_Identifier :
return identifier
var assertStrTmplt = "parse_PrimaryExpression: (Identifier) Unexpected symbol: {value}"
var assertStr = assertStrTmplt.format({"value" : identifier.Type})
assert(true != true, assertStr)
TokenType.sym_This :
return parse_ThisExpression()
TokenType.expr_New :
return parse_NewExpression()
return parse_ResolvedSymbol()
# > PrimaryExpression
# Literal
# : NumericLiteral
# | StringLiteral
# | BooleanLiteral
# | NullLiteral
# ;
func parse_Literal():
match NextToken.Type :
TokenType.literal_Number:
return parse_NumericLiteral()
TokenType.literal_String:
return parse_StringLiteral()
TokenType.literal_BTrue:
return parse_BooleanLiteral(TokenType.literal_BTrue)
TokenType.literal_BFalse:
return parse_BooleanLiteral(TokenType.literal_BFalse)
TokenType.literal_Null:
return parse_NullLiteral()
assert(false, "parse_Literal: Was not able to detect valid literal type from NextToken")
# > PrimaryExpression
# ParenthesizedExpression
# : ( Expression )
# ;
func parse_ParenthesizedExpression():
eat(TokenType.expr_PStart)
var expression = parse_Expression()
eat(TokenType.expr_PEnd)
return expression
# > PrimaryExpression
# ThisExpression
# : this
# ;
func parse_ThisExpression():
eat(TokenType.sym_This)
var \
node = PNode.new()
node.Type = NodeType.expr_This
return node
# > PrimaryExpression
# NewExpression
# : new MemberExpression Arugments -> new MyNamespace.MyClass(1, 2);
# ;
func parse_NewExpression():
eat(TokenType.expr_New)
var memberExp = parse_MemberExpression()
var args = parse_Arguments()
var \
node = PNode.new()
node.Type = NodeType.expr_New
node.Value = [ memberExp, args ]
return node;
# > Literal
# NumericLiteral
# : Number
# ;
func parse_NumericLiteral():
var Token = eat(TokenType.literal_Number)
var \
node = PNode.new()
node.Type = NodeType.literal_Numeric
node.Value = int( Token.Value )
return node
# > Literal
# StringLiteral
# : String
# ;
func parse_StringLiteral():
var Token = eat(TokenType.literal_String)
var \
node = PNode.new()
node.Type = NodeType.literal_String
node.Value = Token.Value.substr( 1, Token.Value.length() - 2 )
return node
# > Literal
# BooleanLiteral
# : true
# | false
# ;
func parse_BooleanLiteral(token):
eat(token)
var value
if (TokenType.literal_BTrue == token) :
value = true
elif (TokenType.literal_BFalse == token) :
value = false
var \
node = PNode.new()
node.Type = NodeType.literal_Bool
node.Value = value
return node
# > Literal
# NullLiteral
# : null
# ;
func parse_NullLiteral():
eat(TokenType.literal_Null)
var \
node = PNode.new()
node.Type = NodeType.literal_Null
node.Value = null
return node