From bae6aa05fc4d2f5aa5c0e681bd692f40f9859431 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 3 Feb 2025 20:23:28 +0100 Subject: [PATCH] begin with variables --- ast/ast.go | 25 ++++++ language.md | 2 +- parser/parser.go | 117 ++++++++++++++++++++--------- tast/tast.go | 32 ++++++++ typechecker/variable_resolution.go | 1 + 5 files changed, 141 insertions(+), 36 deletions(-) create mode 100644 typechecker/variable_resolution.go diff --git a/ast/ast.go b/ast/ast.go index 1d03240..70feafe 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -190,3 +190,28 @@ func (ie *IfExpression) String() string { return builder.String() } + +// This is still a expression, because making it some other type of node would be to much work +type VariableDeclaration struct { + Token token.Token // The Identifier token + InitializingExpression Expression + Type string + Identifier string +} + +func (vd *VariableDeclaration) expressionNode() {} +func (vd *VariableDeclaration) TokenLiteral() string { return vd.Token.Literal } +func (vd *VariableDeclaration) String() string { + return fmt.Sprintf("%s : %v = %s", vd.Identifier, vd.Type, vd.InitializingExpression) +} + +type VariableReference struct { + Token token.Token // The identifier token + Identifier string +} + +func (vr *VariableReference) expressionNode() {} +func (vr *VariableReference) TokenLiteral() string { return vr.Token.Literal } +func (vr *VariableReference) String() string { + return fmt.Sprintf("%s", vr.Identifier) +} diff --git a/language.md b/language.md index 7b92a69..839dc05 100644 --- a/language.md +++ b/language.md @@ -5,7 +5,7 @@ ```tt // Return type is i64 fn main() = { - let i = 34; + i : = 3; i }; ``` diff --git a/parser/parser.go b/parser/parser.go index d5ef3f5..73963aa 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -57,6 +57,7 @@ func New(l *lexer.Lexer) *Parser { p.registerPrefixFn(token.OpenParen, p.parseGroupedExpression) p.registerPrefixFn(token.OpenBrack, p.parseBlockExpression) p.registerPrefixFn(token.If, p.parseIfExpression) + p.registerPrefixFn(token.Ident, p.parseVariable) p.infixParseFns = make(map[token.TokenType]infixParseFn) p.registerInfixFn(token.Plus, p.parseBinaryExpression) @@ -264,41 +265,6 @@ func (p *Parser) parseBooleanExpression() ast.Expression { } } -func (p *Parser) parseBinaryExpression(lhs ast.Expression) ast.Expression { - var op ast.BinaryOperator - switch p.curToken.Type { - case token.Plus: - op = ast.Add - case token.Minus: - op = ast.Subtract - case token.Asterisk: - op = ast.Multiply - case token.Slash: - op = ast.Divide - case token.DoubleEqual: - op = ast.Equal - case token.NotEqual: - op = ast.NotEqual - case token.LessThan: - op = ast.LessThan - case token.LessThanEqual: - op = ast.LessThanEqual - case token.GreaterThan: - op = ast.GreaterThan - case token.GreaterThanEqual: - op = ast.GreaterThanEqual - default: - return p.exprError(p.curToken, "invalid token for binary expression %s", p.curToken.Type) - } - tok := p.curToken - - precedence := p.curPrecedence() - p.nextToken() - rhs := p.parseExpression(precedence) - - return &ast.BinaryExpression{Lhs: lhs, Rhs: rhs, Operator: op, Token: tok} -} - func (p *Parser) parseGroupedExpression() ast.Expression { p.expect(token.OpenParen) @@ -368,3 +334,84 @@ func (p *Parser) parseIfExpression() ast.Expression { return ifExpr } + +func (p *Parser) parseVariable() ast.Expression { + if ok, errExpr := p.expect(token.Ident); !ok { + return errExpr + } + + if p.peekTokenIs(token.Colon) { + return p.parseVariableDeclaration() + } else { + return &ast.VariableReference{ + Token: p.curToken, + Identifier: p.curToken.Literal, + } + } + + // FIXME(Robin): Add variable references + // Lets panic about deez nuts of yours + panic("deez nuts") +} + +func (p *Parser) parseVariableDeclaration() ast.Expression { + if ok, errExpr := p.expect(token.Ident); !ok { + return errExpr + } + + variable := &ast.VariableDeclaration{Token: p.curToken, Identifier: p.curToken.Literal} + if ok, errExpr := p.expectPeek(token.Colon); !ok { + return errExpr + } + + if p.peekTokenIs(token.Ident) { + p.nextToken() + variable.Type = p.curToken.Literal + } + + if ok, errExpr := p.expectPeek(token.Equal); !ok { + return errExpr + } + + p.nextToken() + variable.InitializingExpression = p.parseExpression(PrecLowest) + + return variable +} + +// Binary + +func (p *Parser) parseBinaryExpression(lhs ast.Expression) ast.Expression { + var op ast.BinaryOperator + switch p.curToken.Type { + case token.Plus: + op = ast.Add + case token.Minus: + op = ast.Subtract + case token.Asterisk: + op = ast.Multiply + case token.Slash: + op = ast.Divide + case token.DoubleEqual: + op = ast.Equal + case token.NotEqual: + op = ast.NotEqual + case token.LessThan: + op = ast.LessThan + case token.LessThanEqual: + op = ast.LessThanEqual + case token.GreaterThan: + op = ast.GreaterThan + case token.GreaterThanEqual: + op = ast.GreaterThanEqual + default: + return p.exprError(p.curToken, "invalid token for binary expression %s", p.curToken.Type) + } + tok := p.curToken + + precedence := p.curPrecedence() + p.nextToken() + rhs := p.parseExpression(precedence) + + return &ast.BinaryExpression{Lhs: lhs, Rhs: rhs, Operator: op, Token: tok} +} diff --git a/tast/tast.go b/tast/tast.go index eb0c72b..d1e8bcd 100644 --- a/tast/tast.go +++ b/tast/tast.go @@ -169,3 +169,35 @@ func (ie *IfExpression) String() string { return builder.String() } + +// This is still a expression, because making it some other type of node would be to much work +type VariableDeclaration struct { + Token token.Token // The Identifier token + InitializingExpression Expression + VariableType types.Type + Identifier string +} + +func (vd *VariableDeclaration) expressionNode() {} +func (vd *VariableDeclaration) Type() types.Type { + return vd.VariableType +} +func (vd *VariableDeclaration) TokenLiteral() string { return vd.Token.Literal } +func (vd *VariableDeclaration) String() string { + return fmt.Sprintf("%s : %v = %s", vd.Identifier, vd.Type().Name(), vd.InitializingExpression) +} + +type VariableReference struct { + Token token.Token // The identifier token + Identifier string + VariableType types.Type +} + +func (vr *VariableReference) expressionNode() {} +func (vr *VariableReference) Type() types.Type { + return vr.VariableType +} +func (vr *VariableReference) TokenLiteral() string { return vr.Token.Literal } +func (vr *VariableReference) String() string { + return fmt.Sprintf("%s", vr.Identifier) +} diff --git a/typechecker/variable_resolution.go b/typechecker/variable_resolution.go new file mode 100644 index 0000000..97aa2fb --- /dev/null +++ b/typechecker/variable_resolution.go @@ -0,0 +1 @@ +package typechecker