funcs as expression
This commit is contained in:
parent
e98e0643e2
commit
90eaf081a7
@ -66,6 +66,16 @@ func (as *AssignStatement) String() string {
|
||||
return fmt.Sprintf("%s%s = %s", prefix, nameStr, as.Value.String())
|
||||
}
|
||||
|
||||
// ExpressionStatement represents expressions used as statements
|
||||
type ExpressionStatement struct {
|
||||
Expression Expression
|
||||
}
|
||||
|
||||
func (es *ExpressionStatement) statementNode() {}
|
||||
func (es *ExpressionStatement) String() string {
|
||||
return es.Expression.String()
|
||||
}
|
||||
|
||||
// EchoStatement represents echo output statements
|
||||
type EchoStatement struct {
|
||||
Value Expression
|
||||
|
101
parser/parser.go
101
parser/parser.go
@ -201,7 +201,7 @@ func (p *Parser) ParseProgram() *Program {
|
||||
func (p *Parser) parseStatement() Statement {
|
||||
switch p.curToken.Type {
|
||||
case IDENT:
|
||||
return p.parseAssignStatement()
|
||||
return p.parseIdentifierStatement()
|
||||
case IF:
|
||||
return p.parseIfStatement()
|
||||
case FOR:
|
||||
@ -230,54 +230,68 @@ func (p *Parser) parseStatement() Statement {
|
||||
}
|
||||
}
|
||||
|
||||
// parseAssignStatement parses variable assignment with optional type hint
|
||||
func (p *Parser) parseAssignStatement() *AssignStatement {
|
||||
stmt := &AssignStatement{}
|
||||
|
||||
// Parse left-hand side expression
|
||||
stmt.Name = p.ParseExpression(LOWEST)
|
||||
if stmt.Name == nil {
|
||||
p.addError("expected expression for assignment left-hand side")
|
||||
// parseIdentifierStatement handles both assignments and expression statements starting with identifiers
|
||||
func (p *Parser) parseIdentifierStatement() Statement {
|
||||
// Parse the left-hand side expression first
|
||||
expr := p.ParseExpression(LOWEST)
|
||||
if expr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check for type hint on simple identifiers
|
||||
if _, ok := stmt.Name.(*Identifier); ok {
|
||||
stmt.TypeHint = p.parseTypeHint()
|
||||
// Check for type hint (only valid on simple identifiers)
|
||||
var typeHint *TypeInfo
|
||||
if _, ok := expr.(*Identifier); ok {
|
||||
typeHint = p.parseTypeHint()
|
||||
}
|
||||
|
||||
// Check if next token is assignment operator
|
||||
if !p.peekTokenIs(ASSIGN) {
|
||||
p.addError("unexpected identifier, expected assignment or declaration")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate assignment target and check if it's a declaration
|
||||
switch name := stmt.Name.(type) {
|
||||
case *Identifier:
|
||||
stmt.IsDeclaration = !p.isVariableDeclared(name.Value)
|
||||
if stmt.IsDeclaration {
|
||||
p.declareVariable(name.Value)
|
||||
// Check if this is an assignment
|
||||
if p.peekTokenIs(ASSIGN) {
|
||||
// Convert to assignment statement
|
||||
stmt := &AssignStatement{
|
||||
Name: expr,
|
||||
TypeHint: typeHint,
|
||||
}
|
||||
case *DotExpression, *IndexExpression:
|
||||
stmt.IsDeclaration = false
|
||||
default:
|
||||
p.addError("invalid assignment target")
|
||||
|
||||
// Validate assignment target and check if it's a declaration
|
||||
switch name := expr.(type) {
|
||||
case *Identifier:
|
||||
stmt.IsDeclaration = !p.isVariableDeclared(name.Value)
|
||||
if stmt.IsDeclaration {
|
||||
p.declareVariable(name.Value)
|
||||
}
|
||||
case *DotExpression, *IndexExpression:
|
||||
stmt.IsDeclaration = false
|
||||
default:
|
||||
p.addError("invalid assignment target")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !p.expectPeek(ASSIGN) {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.nextToken()
|
||||
|
||||
stmt.Value = p.ParseExpression(LOWEST)
|
||||
if stmt.Value == nil {
|
||||
p.addError("expected expression after assignment operator")
|
||||
return nil
|
||||
}
|
||||
|
||||
return stmt
|
||||
} else {
|
||||
// This is an expression statement
|
||||
return &ExpressionStatement{Expression: expr}
|
||||
}
|
||||
}
|
||||
|
||||
// parseExpressionStatement parses expressions used as statements
|
||||
func (p *Parser) parseExpressionStatement() *ExpressionStatement {
|
||||
stmt := &ExpressionStatement{}
|
||||
stmt.Expression = p.ParseExpression(LOWEST)
|
||||
if stmt.Expression == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !p.expectPeek(ASSIGN) {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.nextToken()
|
||||
|
||||
stmt.Value = p.ParseExpression(LOWEST)
|
||||
if stmt.Value == nil {
|
||||
p.addError("expected expression after assignment operator")
|
||||
return nil
|
||||
}
|
||||
|
||||
return stmt
|
||||
}
|
||||
|
||||
@ -298,6 +312,11 @@ func (p *Parser) parseEchoStatement() *EchoStatement {
|
||||
|
||||
// parseBreakStatement parses break statements
|
||||
func (p *Parser) parseBreakStatement() *BreakStatement {
|
||||
// Check if break is followed by an identifier (invalid)
|
||||
if p.peekTokenIs(IDENT) {
|
||||
p.addError("unexpected identifier")
|
||||
return nil
|
||||
}
|
||||
return &BreakStatement{}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ func TestParsingErrors(t *testing.T) {
|
||||
{"+ 5", "unexpected operator '+'", 1, 1},
|
||||
{"1 +", "expected expression after operator '+'", 1, 3},
|
||||
{"@", "unexpected token '@'", 1, 1},
|
||||
{"invalid@", "unexpected identifier", 1, 1},
|
||||
{"invalid@", "unexpected token '@'", 1, 1},
|
||||
{"{1, 2", "expected next token to be }", 1, 6},
|
||||
{"{a =", "expected expression after assignment operator", 1, 4},
|
||||
{"{a = 1,", "expected next token to be }", 1, 8},
|
||||
|
Loading…
x
Reference in New Issue
Block a user