Skip to content

Commit 0200f8d

Browse files
committed
Add struct declaration parsing (#51)
1 parent b7467fe commit 0200f8d

4 files changed

Lines changed: 140 additions & 10 deletions

File tree

lexer/lexer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ const (
5656
// Keywords.
5757
IMPORT
5858
TYPE_DECLARATION
59+
STRUCT
5960
CONST_DEFINITION
6061
VAR_DEFINITION
6162
FUNCTION_DEFINITION
@@ -174,6 +175,7 @@ var keywords = map[string]TokenType{
174175
// Common keywords.
175176
"import": IMPORT,
176177
"type": TYPE_DECLARATION,
178+
"struct": STRUCT,
177179
"const": CONST_DEFINITION,
178180
"var": VAR_DEFINITION,
179181
"func": FUNCTION_DEFINITION,

parser/parser.go

Lines changed: 110 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ type foundTypeDefinition struct {
5151

5252
type context struct {
5353
imports map[string]string // Maps import aliases to file hashes.
54-
types map[string]typeDefinition // Stores the defined types.
54+
types map[string]typeDefinition // Stores the declared types.
55+
structs map[string]StructDeclaration // Stores the declared structs.
5556
namedValues map[string][]NamedValue // Stores the variable/constant name to variable/constant relation.
5657
functions map[string]FunctionDefinition // Stores the function name to function relation.
5758
scopeStack []scope // Stores the current scopes.
@@ -63,6 +64,7 @@ func newContext() context {
6364
c := context{
6465
imports: map[string]string{},
6566
types: map[string]typeDefinition{},
67+
structs: map[string]StructDeclaration{},
6668
namedValues: map[string][]NamedValue{},
6769
functions: map[string]FunctionDefinition{},
6870
layer: -1, // Init at -1 since program increases it right away.
@@ -145,7 +147,7 @@ func (c context) addType(typeName string, valueType ValueType, isAlias bool, isE
145147
_, exists := c.findType(typeName, false)
146148

147149
if exists {
148-
return fmt.Errorf("%s has already been defined", typeName)
150+
return fmt.Errorf("type %s has already been defined", typeName)
149151
}
150152
if valueType.IsSlice() {
151153
// TODO: Add support.
@@ -159,6 +161,16 @@ func (c context) addType(typeName string, valueType ValueType, isAlias bool, isE
159161
return nil
160162
}
161163

164+
func (c context) addStruct(structName string, structDeclaration StructDeclaration) error {
165+
_, exists := c.findStruct(structName)
166+
167+
if exists {
168+
return fmt.Errorf("struct %s has already been defined", structName)
169+
}
170+
c.structs[structName] = structDeclaration
171+
return nil
172+
}
173+
162174
func (c context) addNamedValues(prefix string, global bool, namedValues ...NamedValue) error {
163175
for _, namedValue := range namedValues {
164176
prefixedName, err := c.buildPrefixedName(namedValue.Name(), prefix, global, false)
@@ -214,6 +226,11 @@ func (c context) findType(typeName string, searchUntilElementary bool) (foundTyp
214226
return foundDefinition, exists
215227
}
216228

229+
func (c context) findStruct(name string) (StructDeclaration, bool) {
230+
structDeclaration, exists := c.structs[name]
231+
return structDeclaration, exists
232+
}
233+
217234
func (c context) findNamedValue(name string, prefix string, global bool) (NamedValue, bool) {
218235
prefixedName, err := c.buildPrefixedName(name, prefix, global, true)
219236

@@ -246,7 +263,8 @@ func (c context) clone() context {
246263
return context{
247264
imports: maps.Clone(c.imports),
248265
types: maps.Clone(c.types),
249-
namedValues: maps.Clone(c.namedValues),
266+
structs: maps.Clone(c.structs),
267+
namedValues: maps.Clone(c.namedValues), // TODO: Make sure this is appropriate cloning because each entry contains a slice.
250268
functions: maps.Clone(c.functions),
251269
scopeStack: slices.Clone(c.scopeStack),
252270
layer: c.layer,
@@ -361,8 +379,8 @@ func allowedBinaryOperators(t ValueType) []BinaryOperator {
361379
case DATA_TYPE_STRING:
362380
operators = []BinaryOperator{BINARY_OPERATOR_ADDITION}
363381
default:
364-
// For other types no operations are permitted.
365382
}
383+
// For other types no operations are permitted.
366384
}
367385
return operators
368386
}
@@ -859,7 +877,7 @@ func (p *Parser) evaluateImports(ctx context) ([]Statement, error) {
859877
return nil, err
860878
}
861879
regexp := regexp.MustCompile(`package \w+`)
862-
bodyBytes =regexp.ReplaceAll(bodyBytes, []byte("")) // Remove package statemnt.
880+
bodyBytes = regexp.ReplaceAll(bodyBytes, []byte("")) // Remove package statemnt.
863881

864882
err = os.WriteFile(absPath, bodyBytes, 0400)
865883

@@ -1209,6 +1227,66 @@ func (p *Parser) evaluateValueType(ctx context) (ValueType, error) {
12091227
return evaluatedType, nil
12101228
}
12111229

1230+
func (p *Parser) evaluateStructDeclaration(ctx context) (Statement, error) {
1231+
structToken := p.eat()
1232+
1233+
if structToken.Type() != lexer.STRUCT {
1234+
return nil, p.expectedKeywordError("struct", structToken)
1235+
}
1236+
nextToken := p.eat()
1237+
1238+
if nextToken.Type() != lexer.OPENING_CURLY_BRACKET {
1239+
return nil, p.expectedError(`"{"`, nextToken)
1240+
}
1241+
nextToken = p.eat()
1242+
1243+
if nextToken.Type() != lexer.NEWLINE {
1244+
return nil, p.expectedNewlineError(nextToken)
1245+
}
1246+
fields := []StructField{}
1247+
1248+
// Evaluate fields.
1249+
for {
1250+
nameTokens, err := p.evaluateNames()
1251+
1252+
if err != nil {
1253+
return nil, err
1254+
}
1255+
valueTypeToken := p.peek()
1256+
valueType, err := p.evaluateValueType(ctx)
1257+
1258+
if err != nil {
1259+
return nil, err
1260+
}
1261+
1262+
// Don't allow nested structs for now.
1263+
if valueType.DataType() == DATA_TYPE_STRUCT {
1264+
return nil, p.atError("nested structs are not allowed", valueTypeToken)
1265+
}
1266+
1267+
for _, nameToken := range nameTokens {
1268+
fields = append(fields, StructField{
1269+
name: nameToken.Value(),
1270+
valueType: valueType,
1271+
})
1272+
}
1273+
nextToken = p.eat()
1274+
1275+
if nextToken.Type() != lexer.NEWLINE {
1276+
return nil, p.expectedNewlineError(nextToken)
1277+
}
1278+
nextToken = p.peek()
1279+
1280+
if nextToken.Type() == lexer.CLOSING_CURLY_BRACKET {
1281+
p.eat() // Eat closing curly bracket and break.
1282+
break
1283+
}
1284+
}
1285+
return StructDeclaration{
1286+
fields,
1287+
}, nil
1288+
}
1289+
12121290
func (p *Parser) evaluateTypeDeclaration(ctx context) (Statement, error) {
12131291
typeToken := p.eat()
12141292

@@ -1221,20 +1299,42 @@ func (p *Parser) evaluateTypeDeclaration(ctx context) (Statement, error) {
12211299
return nil, p.expectedIdentifierError(nameToken)
12221300
}
12231301
isAlias := false
1302+
assignToken := p.peek()
12241303

12251304
// If a type is assigned to the new type with an assign-operator,
12261305
// then it's just an alias.
1227-
if p.peek().Type() == lexer.ASSIGN_OPERATOR {
1306+
if assignToken.Type() == lexer.ASSIGN_OPERATOR {
12281307
isAlias = true
12291308
p.eat()
12301309
}
1310+
name := nameToken.Value()
12311311
valueTypeToken := p.peek()
1232-
valueType, err := p.evaluateValueType(ctx)
12331312

1234-
if err != nil {
1235-
return nil, err
1313+
var valueType ValueType
1314+
var err error
1315+
1316+
if valueTypeToken.Type() == lexer.STRUCT {
1317+
if isAlias {
1318+
return nil, p.atError("struct alias is not supported", assignToken)
1319+
}
1320+
structDeclaration, err := p.evaluateStructDeclaration(ctx)
1321+
1322+
if err != nil {
1323+
return nil, err
1324+
}
1325+
err = ctx.addStruct(name, structDeclaration.(StructDeclaration))
1326+
1327+
if err != nil {
1328+
return nil, p.atError(err.Error(), nameToken)
1329+
}
1330+
valueType = NewValueType(DATA_TYPE_STRUCT, false)
1331+
} else {
1332+
valueType, err = p.evaluateValueType(ctx)
1333+
1334+
if err != nil {
1335+
return nil, err
1336+
}
12361337
}
1237-
name := nameToken.Value()
12381338
err = ctx.addType(name, valueType, isAlias, false)
12391339

12401340
if err != nil {

parser/struct.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package parser
2+
3+
type StructField struct {
4+
name string
5+
valueType ValueType
6+
}
7+
8+
func (f StructField) Name() string {
9+
return f.name
10+
}
11+
12+
func (f StructField) ValueType() ValueType {
13+
return f.valueType
14+
}
15+
16+
type StructDeclaration struct {
17+
fields []StructField
18+
}
19+
20+
func (d StructDeclaration) StatementType() StatementType {
21+
return STATEMENT_TYPE_STRUCT_DECLARATION
22+
}
23+
24+
func (d StructDeclaration) Fields() []StructField {
25+
return d.fields
26+
}

parser/types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ const (
6565
STATEMENT_TYPE_PROGRAM StatementType = "program"
6666
STATEMENT_TYPE_TYPE_DECLARATION StatementType = "type declaration"
6767
STATEMENT_TYPE_TYPE_DEFINITION StatementType = "type definition"
68+
STATEMENT_TYPE_STRUCT_DECLARATION StatementType = "struct declaration"
6869
STATEMENT_TYPE_BOOL_LITERAL StatementType = "boolean"
6970
STATEMENT_TYPE_INT_LITERAL StatementType = "integer"
7071
STATEMENT_TYPE_STRING_LITERAL StatementType = "string"
@@ -121,6 +122,7 @@ const (
121122
DATA_TYPE_INTEGER DataType = "int"
122123
DATA_TYPE_STRING DataType = "string"
123124
DATA_TYPE_ERROR DataType = "error"
125+
DATA_TYPE_STRUCT DataType = "struct"
124126
)
125127

126128
const (

0 commit comments

Comments
 (0)