Skip to content

Commit

Permalink
added const parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
NotLe0n committed Feb 3, 2025
1 parent 2b249fc commit 5d72919
Show file tree
Hide file tree
Showing 12 changed files with 157 additions and 12 deletions.
21 changes: 21 additions & 0 deletions src/ast/declarations.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ type (
Mod *Module
}

ConstDecl struct {
Range token.Range
Mod *Module // the module in which the variable was declared
CommentTok *token.Token // optional comment (also contained in ast.Comments)
Type ddptypes.Type // type of the variable
NameTok token.Token // identifier name
Val Expression
IsPublic bool // wether the function is marked with öffentliche
IsExternVisible bool // wether the variable is marked as extern visible
}

VarDecl struct {
Range token.Range
CommentTok *token.Token // optional comment (also contained in ast.Comments)
Expand Down Expand Up @@ -92,6 +103,7 @@ type (
)

func (decl *BadDecl) node() {}
func (decl *ConstDecl) node() {}
func (decl *VarDecl) node() {}
func (decl *FuncDecl) node() {}
func (decl *FuncDef) node() {}
Expand All @@ -100,6 +112,7 @@ func (decl *TypeAliasDecl) node() {}
func (decl *TypeDefDecl) node() {}

func (decl *BadDecl) String() string { return "BadDecl" }
func (decl *ConstDecl) String() string { return "ConstDecl" }
func (decl *VarDecl) String() string { return "VarDecl" }
func (decl *FuncDecl) String() string { return "FuncDecl" }
func (decl *FuncDef) String() string { return "FuncDef" }
Expand All @@ -108,6 +121,7 @@ func (decl *TypeAliasDecl) String() string { return "TypeAliasDecl" }
func (decl *TypeDefDecl) String() string { return "TypeDefDecl" }

func (decl *BadDecl) Token() token.Token { return decl.Tok }
func (decl *ConstDecl) Token() token.Token { return decl.NameTok }
func (decl *VarDecl) Token() token.Token { return decl.NameTok }
func (decl *FuncDecl) Token() token.Token { return decl.Tok }
func (decl *FuncDef) Token() token.Token { return decl.Tok }
Expand All @@ -116,6 +130,7 @@ func (decl *TypeAliasDecl) Token() token.Token { return decl.Tok }
func (decl *TypeDefDecl) Token() token.Token { return decl.Tok }

func (decl *BadDecl) GetRange() token.Range { return decl.Err.Range }
func (decl *ConstDecl) GetRange() token.Range { return decl.Range }
func (decl *VarDecl) GetRange() token.Range { return decl.Range }
func (decl *FuncDecl) GetRange() token.Range { return decl.Range }
func (decl *FuncDef) GetRange() token.Range { return decl.Range }
Expand All @@ -124,6 +139,7 @@ func (decl *TypeAliasDecl) GetRange() token.Range { return decl.Range }
func (decl *TypeDefDecl) GetRange() token.Range { return decl.Range }

func (decl *BadDecl) Accept(visitor FullVisitor) VisitResult { return visitor.VisitBadDecl(decl) }
func (decl *ConstDecl) Accept(visitor FullVisitor) VisitResult { return visitor.VisitConstDecl(decl) }
func (decl *VarDecl) Accept(visitor FullVisitor) VisitResult { return visitor.VisitVarDecl(decl) }
func (decl *FuncDecl) Accept(visitor FullVisitor) VisitResult { return visitor.VisitFuncDecl(decl) }
func (decl *FuncDef) Accept(visitor FullVisitor) VisitResult { return visitor.VisitFuncDef(decl) }
Expand All @@ -137,6 +153,7 @@ func (decl *TypeDefDecl) Accept(visitor FullVisitor) VisitResult {
}

func (decl *BadDecl) declarationNode() {}
func (decl *ConstDecl) declarationNode() {}
func (decl *VarDecl) declarationNode() {}
func (decl *FuncDecl) declarationNode() {}
func (decl *FuncDef) statementNode() {}
Expand All @@ -145,27 +162,31 @@ func (decl *TypeAliasDecl) declarationNode() {}
func (decl *TypeDefDecl) declarationNode() {}

func (decl *BadDecl) Name() string { return "" }
func (decl *ConstDecl) Name() string { return decl.NameTok.Literal }
func (decl *VarDecl) Name() string { return decl.NameTok.Literal }
func (decl *FuncDecl) Name() string { return decl.NameTok.Literal }
func (decl *StructDecl) Name() string { return decl.NameTok.Literal }
func (decl *TypeAliasDecl) Name() string { return decl.NameTok.Literal }
func (decl *TypeDefDecl) Name() string { return decl.NameTok.Literal }

func (decl *BadDecl) Public() bool { return false }
func (decl *ConstDecl) Public() bool { return decl.IsPublic }
func (decl *VarDecl) Public() bool { return decl.IsPublic }
func (decl *FuncDecl) Public() bool { return decl.IsPublic }
func (decl *StructDecl) Public() bool { return decl.IsPublic }
func (decl *TypeAliasDecl) Public() bool { return decl.IsPublic }
func (decl *TypeDefDecl) Public() bool { return decl.IsPublic }

func (decl *BadDecl) Comment() *token.Token { return nil }
func (decl *ConstDecl) Comment() *token.Token { return decl.CommentTok }
func (decl *VarDecl) Comment() *token.Token { return decl.CommentTok }
func (decl *FuncDecl) Comment() *token.Token { return decl.CommentTok }
func (decl *StructDecl) Comment() *token.Token { return decl.CommentTok }
func (decl *TypeAliasDecl) Comment() *token.Token { return decl.CommentTok }
func (decl *TypeDefDecl) Comment() *token.Token { return decl.CommentTok }

func (decl *BadDecl) Module() *Module { return decl.Mod }
func (decl *ConstDecl) Module() *Module { return decl.Mod }
func (decl *VarDecl) Module() *Module { return decl.Mod }
func (decl *FuncDecl) Module() *Module { return decl.Mod }
func (decl *StructDecl) Module() *Module { return decl.Mod }
Expand Down
8 changes: 8 additions & 0 deletions src/ast/helper_visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,14 @@ func (h *helperVisitor) VisitBadDecl(decl *BadDecl) VisitResult {
return VisitRecurse
}

func (h *helperVisitor) VisitConstDecl(decl *ConstDecl) VisitResult {
result := VisitRecurse
if vis, ok := h.actualVisitor.(ConstDeclVisitor); ok {
result = vis.VisitConstDecl(decl)
}
return h.visitChildren(result, decl.Val)
}

func (h *helperVisitor) VisitVarDecl(decl *VarDecl) VisitResult {
result := VisitRecurse
if vis, ok := h.actualVisitor.(VarDeclVisitor); ok {
Expand Down
9 changes: 9 additions & 0 deletions src/ast/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ func (pr *printer) VisitBadDecl(decl *BadDecl) VisitResult {
return VisitRecurse
}

func (pr *printer) VisitConstDecl(decl *ConstDecl) VisitResult {
msg := fmt.Sprintf("ConstDecl[%s: %s]", decl.Name(), decl.Type)
if decl.CommentTok != nil {
msg += fmt.Sprintf(commentFmt, strings.Trim(decl.CommentTok.Literal, commentCutset), pr.currentIdent, " ")
}
pr.parenthesizeNode(msg, decl.Val)
return VisitRecurse
}

func (pr *printer) VisitVarDecl(decl *VarDecl) VisitResult {
msg := fmt.Sprintf("VarDecl[%s: %s]", decl.Name(), decl.Type)
if decl.CommentTok != nil {
Expand Down
14 changes: 14 additions & 0 deletions src/ast/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type FullVisitor interface {
*/

BadDeclVisitor
ConstDeclVisitor
VarDeclVisitor
FuncDeclVisitor
FuncDefVisitor
Expand Down Expand Up @@ -80,6 +81,10 @@ type (
Visitor
VisitBadDecl(*BadDecl) VisitResult
}
ConstDeclVisitor interface {
Visitor
VisitConstDecl(*ConstDecl) VisitResult
}
VarDeclVisitor interface {
Visitor
VisitVarDecl(*VarDecl) VisitResult
Expand Down Expand Up @@ -247,6 +252,15 @@ func (f BadDeclVisitorFunc) VisitBadDecl(stmt *BadDecl) VisitResult {
return f(stmt)
}

type ConstDeclVisitorFunc func(*ConstDecl) VisitResult

var _ ConstDeclVisitor = (ConstDeclVisitorFunc)(nil)

func (ConstDeclVisitorFunc) Visitor() {}
func (f ConstDeclVisitorFunc) VisitConstDecl(stmt *ConstDecl) VisitResult {
return f(stmt)
}

type VarDeclVisitorFunc func(*VarDecl) VisitResult

var _ VarDeclVisitor = (VarDeclVisitorFunc)(nil)
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,10 @@ func (c *compiler) VisitBadDecl(d *ast.BadDecl) ast.VisitResult {
return ast.VisitRecurse
}

func (c *compiler) VisitConstDecl(d *ast.ConstDecl) ast.VisitResult {
return ast.VisitRecurse
}

func (c *compiler) VisitVarDecl(d *ast.VarDecl) ast.VisitResult {
// allocate the variable on the function call frame
// all local variables are allocated in the first basic block of the function they are within
Expand Down
2 changes: 1 addition & 1 deletion src/ddperror/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func MsgGotExpected(got any, expected ...any) string {
}

func MsgNameAlreadyExists(name string) string {
return fmt.Sprintf("Der Name %s steht bereits für eine Variable, Funktion oder Struktur", name)
return fmt.Sprintf("Der Name %s steht bereits für eine Variable, Konstante, Funktion oder Struktur", name)
}

func MsgAliasAlreadyExists(alias, name string, isFunc bool) string {
Expand Down
78 changes: 68 additions & 10 deletions src/parser/declarations.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,71 @@ func (p *parser) assignRhs(withComma bool) ast.Expression {
return expr
}

func (p *parser) matchExternSichtbar() bool {
if p.matchAny(token.COMMA) || p.matchAny(token.EXTERN) {
if p.previous().Type == token.COMMA {
p.consumeSeq(token.EXTERN)
}
p.consumeSeq(token.SICHTBARE)
return true
}
return false
}

func (p *parser) constDeclaration(startDepth int) ast.Declaration {
begin := p.peekN(startDepth) // Die
if begin.Type != token.DIE {
p.err(ddperror.SYN_GENDER_MISMATCH, begin.Range, fmt.Sprintf("Falscher Artikel, meintest du %s?", "Die"))
}

comment := p.parseDeclComment(begin.Range)

isPublic := p.peekN(startDepth+1).Type == token.OEFFENTLICHE || p.peekN(startDepth+1).Type == token.OEFFENTLICHEN
isExternVisible := isPublic && p.matchExternSichtbar()

p.consumeSeq(token.KONSTANTE)

// we need a name, so bailout if none is provided
if !p.consumeSeq(token.IDENTIFIER) {
return &ast.BadDecl{
Err: ddperror.Error{
Range: token.NewRange(p.peekN(-2), p.peek()),
File: p.module.FileName,
Msg: "Es wurde ein Name für die Konstante erwartet",
},
Tok: *p.peek(),
Mod: p.module,
}
}
name := p.previous()

p.consumeSeq(token.IST)

expr := p.assignRhs(false) // TODO: add support for lists "N Mal x"
p.consumeSeq(token.DOT)

switch expr := expr.(type) {
case *ast.IntLit, *ast.FloatLit, *ast.BoolLit, *ast.StringLit, *ast.CharLit, *ast.ListLit:
default:
p.err(ddperror.SYN_EXPECTED_LITERAL, expr.GetRange(), "Es wurde ein Literal erwartet aber ein Ausdruck gefunden")
}

// prefer trailing comments as long as they are on the same line
if trailingComment := p.commentAfterPos(p.previous().Range.End); trailingComment != nil && trailingComment.Range.Start.Line == p.previous().Range.End.Line {
comment = trailingComment
}

return &ast.ConstDecl{
Range: token.NewRange(begin, p.previous()),
Mod: p.module,
CommentTok: comment,
IsPublic: isPublic,
IsExternVisible: isExternVisible,
NameTok: *name,
Val: expr,
}
}

// parses a variable declaration
// startDepth is the int passed to p.peekN(n) to get to the DER/DIE token of the declaration
// isField indicates that this declaration should be parsed as a struct field
Expand All @@ -74,15 +139,7 @@ func (p *parser) varDeclaration(startDepth int, isField bool) ast.Declaration {
comment := p.parseDeclComment(begin.Range)

isPublic := p.peekN(startDepth+1).Type == token.OEFFENTLICHE || p.peekN(startDepth+1).Type == token.OEFFENTLICHEN

isExternVisible := false
if isPublic && p.matchAny(token.COMMA) || p.matchAny(token.EXTERN) {
if p.previous().Type == token.COMMA {
p.consumeSeq(token.EXTERN)
}
p.consumeSeq(token.SICHTBARE)
isExternVisible = true
}
isExternVisible := isPublic && p.matchExternSichtbar()

type_start := p.peek()
typ := p.parseType()
Expand Down Expand Up @@ -122,7 +179,7 @@ func (p *parser) varDeclaration(startDepth int, isField bool) ast.Declaration {
Err: ddperror.Error{
Range: token.NewRange(p.peekN(-2), p.peek()),
File: p.module.FileName,
Msg: "Es wurde ein Variablen Name erwartet",
Msg: "Es wurde ein Name für die Variable erwartet",
},
Tok: *p.peek(),
Mod: p.module,
Expand Down Expand Up @@ -158,6 +215,7 @@ func (p *parser) varDeclaration(startDepth int, isField bool) ast.Declaration {
if !isField {
p.consumeSeq(token.DOT)
}

// prefer trailing comments as long as they are on the same line
if trailingComment := p.commentAfterPos(p.previous().Range.End); trailingComment != nil && trailingComment.Range.Start.Line == p.previous().Range.End.Line {
comment = trailingComment
Expand Down
2 changes: 2 additions & 0 deletions src/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ func (p *parser) declaration() ast.Statement {
case token.FUNKTION:
p.advance()
return p.funcDeclaration(n - 1)
case token.KONSTANTE:
return &ast.DeclStmt{Decl: p.constDeclaration(n)}
default:
return &ast.DeclStmt{Decl: p.varDeclaration(n, false)}
}
Expand Down
17 changes: 17 additions & 0 deletions src/parser/resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,23 @@ func (r *Resolver) VisitBadDecl(decl *ast.BadDecl) ast.VisitResult {
return ast.VisitRecurse
}

func (r *Resolver) VisitConstDecl(decl *ast.ConstDecl) ast.VisitResult {
r.visit(decl.Val)

// insert the variable into the current scope (SymbolTable)
if existed := r.CurrentTable.InsertDecl(decl.Name(), decl); existed {
r.err(ddperror.SEM_NAME_ALREADY_DEFINED, decl.NameTok.Range, ddperror.MsgNameAlreadyExists(decl.Name())) // variables may only be declared once in the same scope
}

if decl.Public() && !ast.IsGlobalScope(r.CurrentTable) {
r.err(ddperror.SEM_NON_GLOBAL_PUBLIC_DECL, decl.NameTok.Range, "Nur globale Konstante können öffentlich sein")
} else if _, alreadyExists := r.Module.PublicDecls[decl.Name()]; decl.IsPublic && !alreadyExists { // insert the variable int othe public module decls
r.Module.PublicDecls[decl.Name()] = decl
}

return ast.VisitRecurse
}

func (r *Resolver) VisitVarDecl(decl *ast.VarDecl) ast.VisitResult {
r.visit(decl.InitVal) // resolve the initial value
// insert the variable into the current scope (SymbolTable)
Expand Down
1 change: 0 additions & 1 deletion src/parser/typechecker/assignable_checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ func isAssignable(expr ast.Expression) (ast.Assigneable, bool) {
default:
return nil, false
}
return nil, false
}

func isBinaryExprAssignable(expr *ast.BinaryExpr) (ast.Assigneable, bool) {
Expand Down
10 changes: 10 additions & 0 deletions src/parser/typechecker/typechecker.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ func (t *Typechecker) VisitBadDecl(decl *ast.BadDecl) ast.VisitResult {
return ast.VisitRecurse
}

func (t *Typechecker) VisitConstDecl(decl *ast.ConstDecl) ast.VisitResult {
decl.Type = t.Evaluate(decl.Val)

if decl.Public() && !IsPublicType(decl.Type, t.CurrentTable) {
t.err(ddperror.SEM_BAD_PUBLIC_MODIFIER, decl.Range, "Der Typ einer öffentlichen Konstante muss ebenfalls öffentlich sein")
}

return ast.VisitRecurse
}

func (t *Typechecker) VisitVarDecl(decl *ast.VarDecl) ast.VisitResult {
initialType := t.Evaluate(decl.InitVal)
decl.InitType = initialType
Expand Down
3 changes: 3 additions & 0 deletions src/token/token_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ const (
ALLE
MODULE
INDEX
KONSTANTE

DOT // .
COMMA // ,
Expand Down Expand Up @@ -325,6 +326,7 @@ var tokenStrings = [...]string{
ALLE: "alle",
MODULE: "Module",
INDEX: "Index",
KONSTANTE: "Konstante",

DOT: ".",
COMMA: ",",
Expand Down Expand Up @@ -497,6 +499,7 @@ var KeywordMap = map[string]TokenType{
"alle": ALLE,
"Module": MODULE,
"Index": INDEX,
"Konstante": KONSTANTE,
}

func KeywordToTokenType(keyword string) TokenType {
Expand Down

0 comments on commit 5d72919

Please sign in to comment.