diff --git a/examples/basic/main.arf b/examples/basic/main.arf index 7084112..12847f7 100644 --- a/examples/basic/main.arf +++ b/examples/basic/main.arf @@ -4,6 +4,6 @@ require "io" func ro main > arguments:{String ..} - < status:Int 0 + < status:Int:<0> --- io.println "hello world" diff --git a/examples/full/main.arf b/examples/full/main.arf index 0817ddd..a05acbc 100644 --- a/examples/full/main.arf +++ b/examples/full/main.arf @@ -5,18 +5,18 @@ require "io" --- # this is a global variable -data pv helloText:String "Hello, world!" +data pv helloText:String:<"Hello, world!"> # this is a struct definition -objt ro Greeter:Obj - rw text:String "Hi." +type ro Greeter:Obj:( + .rw text:String:<"Hi.">) # this is a function func ro main > arguments:{String ..} - < status:Int 0 + < status:Int:<0> --- - = greeter:Greeter:mut + let greeter:Greeter:mut greeter.setText helloText greeter.greet diff --git a/lexer/lexer.go b/lexer/lexer.go index d5e1bf7..c49154c 100644 --- a/lexer/lexer.go +++ b/lexer/lexer.go @@ -192,6 +192,16 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) { token.kind = TokenKindComma lexer.addToken(token) err = lexer.nextRune() + case '(': + token := lexer.newToken() + token.kind = TokenKindLParen + lexer.addToken(token) + err = lexer.nextRune() + case ')': + token := lexer.newToken() + token.kind = TokenKindRParen + lexer.addToken(token) + err = lexer.nextRune() case '[': token := lexer.newToken() token.kind = TokenKindLBracket diff --git a/lexer/lexer_test.go b/lexer/lexer_test.go index 932c9be..623410c 100644 --- a/lexer/lexer_test.go +++ b/lexer/lexer_test.go @@ -138,6 +138,8 @@ func TestTokenizeAll (test *testing.T) { quickToken(1, TokenKindDot, nil), quickToken(1, TokenKindComma, nil), quickToken(2, TokenKindElipsis, nil), + quickToken(1, TokenKindLParen, nil), + quickToken(1, TokenKindRParen, nil), quickToken(1, TokenKindLBracket, nil), quickToken(1, TokenKindRBracket, nil), quickToken(1, TokenKindLBrace, nil), diff --git a/lexer/token.go b/lexer/token.go index c8b6624..033bd06 100644 --- a/lexer/token.go +++ b/lexer/token.go @@ -28,6 +28,8 @@ const ( TokenKindElipsis TokenKindComma + TokenKindLParen + TokenKindRParen TokenKindLBracket TokenKindRBracket TokenKindLBrace @@ -166,6 +168,10 @@ func (tokenKind TokenKind) Describe () (description string) { description = "Elipsis" case TokenKindComma: description = "Comma" + case TokenKindLParen: + description = "LParen" + case TokenKindRParen: + description = "RParen" case TokenKindLBracket: description = "LBracket" case TokenKindRBracket: diff --git a/parser/accessors.go b/parser/accessors.go index bdfcd72..952402f 100644 --- a/parser/accessors.go +++ b/parser/accessors.go @@ -29,12 +29,6 @@ func (section TypeSection) Kind () (kind SectionKind) { return } -// Kind returns the section's kind (SectionKindObjt). -func (section ObjtSection) Kind () (kind SectionKind) { - kind = SectionKindObjt - return -} - // Kind returns the section's kind (SectionKindEnum). func (section EnumSection) Kind () (kind SectionKind) { kind = SectionKindEnum @@ -111,23 +105,23 @@ func (what Type) Points () (points Type) { return } -// Values returns an iterator for the initialization values. -func (values ObjectInitializationValues) Sections () ( - iterator types.Iterator[Argument], -) { - iterator = types.NewIterator(values.attributes) +// MembersLength returns the amount of new members the type specifier defines. +// If it defines no new members, it returns zero. +func (what Type) MembersLength () (length int) { + length = len(what.members) return } -// Length returns the amount of values. -func (values ArrayInitializationValues) Length () (length int) { - length = len(values.values) +// Member returns the member at index. +func (what Type) Member (index int) (member TypeMember) { + member = what.members[index] return } -// Item returns the value at index. -func (values ArrayInitializationValues) Value (index int) (value Argument) { - value = values.values[index] +// BitWidth returns the bit width of the type member. If it is zero, it should +// be treated as unspecified. +func (member TypeMember) BitWidth () (width uint64) { + width = member.bitWidth return } @@ -144,25 +138,6 @@ func (argument Argument) Value () (value any) { return } -// BitWidth returns the bit width of the object member. If it is zero, it should -// be treated as unspecified. -func (member ObjtMember) BitWidth () (width uint64) { - width = member.bitWidth - return -} - -// Length returns the amount of members in the section. -func (section ObjtSection) Length () (length int) { - length = len(section.members) - return -} - -// Item returns the member at index. -func (section ObjtSection) Item (index int) (member ObjtMember) { - member = section.members[index] - return -} - // Length returns the amount of members in the section. func (section EnumSection) Length () (length int) { length = len(section.members) @@ -272,12 +247,6 @@ func (section FuncSection) OutputsLength () (length int) { return } -// Output returns the output at index. -func (section FuncSection) Output (index int) (output FuncOutput) { - output = section.outputs[index] - return -} - // Root returns the root block of the section. func (section FuncSection) Root () (root Block) { root = section.root diff --git a/parser/body.go b/parser/body.go index bb852a0..ba29ab9 100644 --- a/parser/body.go +++ b/parser/body.go @@ -23,12 +23,6 @@ func (parser *ParsingOperation) parseBody () (err error) { if err != nil { return } if parseErr != nil { return parseErr } - case "objt": - section, parseErr := parser.parseObjtSection() - err = parser.tree.addSection(section) - if err != nil { return } - if parseErr != nil { return parseErr } - case "face": section, parseErr := parser.parseFaceSection() err = parser.tree.addSection(section) diff --git a/parser/data.go b/parser/data.go index 52cb5e3..313a909 100644 --- a/parser/data.go +++ b/parser/data.go @@ -35,18 +35,18 @@ func (parser *ParsingOperation) parseDataSection () ( return } - if parser.token.Is(lexer.TokenKindNewline) { - err = parser.nextToken() - if err != nil { return } - - // check if external - if !parser.token.Is(lexer.TokenKindIndent) { return } - if parser.token.Value().(int) != 1 { return } + err = parser.expect(lexer.TokenKindNewline) + if err != nil { return } + err = parser.nextToken() + if err != nil { return } + + // check if data is external + if parser.token.Is(lexer.TokenKindIndent) && + parser.token.Value().(int) == 1 { - err = parser.nextToken() + err = parser.nextToken(lexer.TokenKindName) if err != nil { return } - if parser.token.Is(lexer.TokenKindName) && - parser.token.Value().(string) == "external" { + if parser.token.Value().(string) == "external" { section.external = true err = parser.nextToken(lexer.TokenKindNewline) @@ -56,18 +56,7 @@ func (parser *ParsingOperation) parseDataSection () ( return } - // otherwise, parse initialization values parser.previousToken() - section.value, err = parser.parseInitializationValues(0) - if err != nil { return } - } else { - section.value, err = parser.parseArgument() - if err != nil { return } - - err = parser.expect(lexer.TokenKindNewline) - if err != nil { return } - err = parser.nextToken() - if err != nil { return } } return } diff --git a/parser/data_test.go b/parser/data_test.go index f6b7df3..30739c1 100644 --- a/parser/data_test.go +++ b/parser/data_test.go @@ -6,13 +6,14 @@ func TestData (test *testing.T) { checkTree ("../tests/parser/data", false, `:arf --- -data ro aInteger:Int 3202 -data ro bMutInteger:Int:mut 3202 +data ro aInteger:Int:<3202> +data ro bMutInteger:Int:mut:<3202> data ro cIntegerPointer:{Int} data ro dMutIntegerPointer:{Int}:mut data ro eIntegerArray16:Int:16 data ro fIntegerArrayVariable:{Int ..} -data ro gIntegerArrayInitialized:Int:16 +data ro gIntegerArrayInitialized:Int:16: + < 3948 293 293049 @@ -24,20 +25,35 @@ data ro gIntegerArrayInitialized:Int:16 0 4785 92 -data ro jObject:thing.Thing.thing.thing - .that 2139 - .this 324 -data ro kNestedObject:Obj - .that - .bird2 123.8439 - .bird3 9328.21348239 - .this - .bird0 324 - .bird1 "hello world" + > +data rw hIntegerPointerInit:{Int}:<[& integer]> +data rw iMutIntegerPointerInit:{Int}:mut:<[& integer]> +data ro jObject:Obj: + ( + .that:<324> + .this:<324> + ) +data ro kNestedObject:Obj: + ( + .ro newMember:Int:<9023> + ): + ( + .that: + ( + .bird2:<123.8439> + .bird3:<9328.21348239> + ) + .this: + ( + .bird0:<324> + .bird1:<"hello world"> + ) + ) data ro lMutIntegerArray16:Int:16:mut data ro mExternalData:Int:8 external -data ro nIntegerArrayInitialized:Int:16:mut +data ro nIntegerArrayInitialized:Int:16:mut: + < 3948 293 293049 @@ -49,5 +65,6 @@ data ro nIntegerArrayInitialized:Int:16:mut 0 4785 92 + > `, test) } diff --git a/parser/default-values.go b/parser/default-values.go new file mode 100644 index 0000000..cc8b1df --- /dev/null +++ b/parser/default-values.go @@ -0,0 +1,180 @@ +package parser +// +// import "git.tebibyte.media/arf/arf/lexer" +// import "git.tebibyte.media/arf/arf/infoerr" +// +// // TODO: +// // (parser *ParsingOperation) parseDefaultValues +// +// // (parser *ParsingOperation) parseDefaultMemberValues (return tree of new members and a tree of member values) +// // (parser *ParsingOperation) parseDefaultArrayValues +// +// // (parser *ParsingOperation) parseDefaultMemberValue +// // (parser *ParsingOperation) parseMemberDeclaration +// +// // parsedefaultValues starts on the line after a = phrase, a data section, a +// // type section, or anywhere else where there can be a default value. It returns +// // a default value in the form of an argument, as well as any defined members +// // that it finds. +// func (parser *ParsingOperation) parseDefaultValues ( + // baseIndent int, +// ) ( + // argument Argument, + // members []TypeMember, + // err error, +// ) { + // // check if line is indented one more than baseIndent + // if !parser.token.Is(lexer.TokenKindIndent) { return } + // if parser.token.Value().(int) != baseIndent + 1 { return } +// + // argument.location = parser.token.Location() + // + // err = parser.nextToken() + // if err != nil { return } +// + // if parser.token.Is(lexer.TokenKindDot) { +// + // // object initialization + // parser.previousToken() + // var values ObjectDefaultValues + // values, err = parser.parseObjectdefaultValues() + // argument.kind = ArgumentKindObjectDefaultValues + // argument.value = values + // + // } else { + // + // // array initialization + // parser.previousToken() + // var values ArrayDefaultValues + // values, err = parser.parseArrayDefaultValues() + // argument.kind = ArgumentKindArrayDefaultValues + // argument.value = values + // } + // + // return +// } +// +// // parseObjectdefaultValues parses a list of object initialization +// // values until the indentation level drops. +// func (parser *ParsingOperation) parseObjectdefaultValues () ( + // defaultValues ObjectDefaultValues, + // err error, +// ) { + // defaultValues.attributes = make(map[string] Argument) +// + // baseIndent := 0 + // begin := true + // + // for { + // // if there is no indent we can just stop parsing + // if !parser.token.Is(lexer.TokenKindIndent) { break} + // indent := parser.token.Value().(int) + // + // if begin == true { + // defaultValues.location = parser.token.Location() + // baseIndent = indent + // begin = false + // } +// + // // do not parse any further if the indent has changed + // if indent != baseIndent { break } +// + // // move on to the beginning of the line, which must contain + // // a member initialization value + // err = parser.nextToken(lexer.TokenKindDot) + // if err != nil { return } + // err = parser.nextToken(lexer.TokenKindName) + // if err != nil { return } + // name := parser.token.Value().(string) +// + // // if the member has already been listed, throw an error + // _, exists := defaultValues.attributes[name] + // if exists { + // err = parser.token.NewError ( + // "duplicate member \"" + name + "\" in object " + + // "member initialization", + // infoerr.ErrorKindError) + // return + // } +// + // // parse the argument determining the member initialization + // // value + // err = parser.nextToken() + // if err != nil { return } + // var value Argument + // if parser.token.Is(lexer.TokenKindNewline) { + // + // // recurse + // err = parser.nextToken(lexer.TokenKindIndent) + // if err != nil { return } + // + // value, err = parser.parseDefaultValues(baseIndent) + // defaultValues.attributes[name] = value + // if err != nil { return } + // + // } else { +// + // // parse as normal argument + // value, err = parser.parseArgument() + // defaultValues.attributes[name] = value + // if err != nil { return } + // + // err = parser.expect(lexer.TokenKindNewline) + // if err != nil { return } + // err = parser.nextToken() + // if err != nil { return } + // } + // } + // + // return +// } +// +// // parseArrayDefaultValues parses a list of array initialization values until +// // the indentation lexel drops. +// func (parser *ParsingOperation) parseArrayDefaultValues () ( + // defaultValues ArrayDefaultValues, + // err error, +// ) { + // baseIndent := 0 + // begin := true + // + // for { + // // if there is no indent we can just stop parsing + // if !parser.token.Is(lexer.TokenKindIndent) { break} + // indent := parser.token.Value().(int) + // + // if begin == true { + // defaultValues.location = parser.token.Location() + // baseIndent = indent + // begin = false + // } +// + // // do not parse any further if the indent has changed + // if indent != baseIndent { break } +// + // // move on to the beginning of the line, which must contain + // // arguments + // err = parser.nextToken(validArgumentStartTokens...) + // if err != nil { return } +// + // for { + // // stop parsing this line and go on to the next if a + // // newline token is encountered + // if parser.token.Is(lexer.TokenKindNewline) { + // err = parser.nextToken() + // if err != nil { return } + // break + // } +// + // // otherwise, parse the argument + // var argument Argument + // argument, err = parser.parseArgument() + // if err != nil { return } + // defaultValues.values = append ( + // defaultValues.values, + // argument) + // } + // } +// + // return +// } diff --git a/parser/enum.go b/parser/enum.go index 9625dc5..c2427d9 100644 --- a/parser/enum.go +++ b/parser/enum.go @@ -61,34 +61,62 @@ func (parser *ParsingOperation) parseEnumMembers ( // if we've left the block, stop parsing if !parser.token.Is(lexer.TokenKindIndent) { return } if parser.token.Value().(int) != 1 { return } - - member := EnumMember { } - - // get name - err = parser.nextToken(lexer.TokenKindName) + err = parser.nextToken(lexer.TokenKindMinus) + if err != nil { return } + + var member EnumMember + member, err = parser.parseEnumMember() + into.members = append(into.members, member) + if err != nil { return } + + err = parser.expect(lexer.TokenKindNewline) if err != nil { return } - member.location = parser.token.Location() - member.name = parser.token.Value().(string) err = parser.nextToken() if err != nil { return } - - // parse default value - if parser.token.Is(lexer.TokenKindNewline) { - err = parser.nextToken() - if err != nil { return } + } +} - member.value, err = parser.parseInitializationValues(1) - into.members = append(into.members, member) - if err != nil { return } - } else { - member.value, err = parser.parseArgument() - into.members = append(into.members, member) - if err != nil { return } +// parseEnumMember parses a single enum member. Indenttion level is assumed. +func (parser *ParsingOperation) parseEnumMember () ( + member EnumMember, + err error, +) { + err = parser.expect(lexer.TokenKindMinus) + if err != nil { return } - err = parser.expect(lexer.TokenKindNewline) + // get name + err = parser.nextToken(lexer.TokenKindName) + if err != nil { return } + member.location = parser.token.Location() + member.name = parser.token.Value().(string) + + // see if value exists + err = parser.nextToken ( + lexer.TokenKindColon, + lexer.TokenKindNewline) + if err != nil { return } + + if parser.token.Is(lexer.TokenKindColon) { + err = parser.nextToken() + if err != nil { return } + err = parser.skipWhitespace() + if err != nil { return } + err = parser.expect ( + lexer.TokenKindLessThan, + lexer.TokenKindLParen) + if err != nil { return } + + if parser.token.Is(lexer.TokenKindLessThan) { + // parse value + member.value, err = parser.parseBasicDefaultValue() if err != nil { return } - err = parser.nextToken() + + } else if parser.token.Is(lexer.TokenKindLParen) { + // parse default values + member.value, err = parser.parseObjectDefaultValue() if err != nil { return } } } + + return } diff --git a/parser/enum_test.go b/parser/enum_test.go index bdc57e5..74c59b7 100644 --- a/parser/enum_test.go +++ b/parser/enum_test.go @@ -7,32 +7,63 @@ func TestEnum (test *testing.T) { `:arf --- enum ro AffrontToGod:Int:4 - bird0 + - bird0: + < 28394 9328 398 9 - bird1 + > + - bird1: + < 23 932832 398 2349 - bird2 + > + - bird2: + < 1 2 3 4 + > enum ro NamedColor:U32 - red 16711680 - green 65280 - blue 255 + - red:<16711680> + - green:<65280> + - blue:<255> +enum ro ThisIsTerrible:Obj: + ( + .rw x:Int + .rw y:Int + ) + - up: + ( + .x:<0> + .y:<-1> + ) + - down: + ( + .x:<0> + .y:<1> + ) + - left: + ( + .x:<-1> + .y:<0> + ) + - right: + ( + .x:<1> + .y:<0> + ) enum ro Weekday:Int - sunday - monday - tuesday - wednesday - thursday - friday - saturday + - sunday + - monday + - tuesday + - wednesday + - thursday + - friday + - saturday `, test) } diff --git a/parser/func.go b/parser/func.go index 1722d9f..7e775c5 100644 --- a/parser/func.go +++ b/parser/func.go @@ -171,7 +171,7 @@ func (parser *ParsingOperation) parseFuncArguments ( if err != nil { return } case lexer.TokenKindLessThan: - output := FuncOutput { } + output := Declaration { } output.location = parser.token.Location() // get name @@ -186,34 +186,13 @@ func (parser *ParsingOperation) parseFuncArguments ( if err != nil { return } output.what, err = parser.parseType() if err != nil { return } - - // skip the default value if we are skimming - if parser.skimming { - err = parser.skipIndentLevel(2) - into.outputs = append(into.outputs, output) - return - } - // parse default value - if parser.token.Is(lexer.TokenKindNewline) { - err = parser.nextToken() - if err != nil { return } + into.outputs = append(into.outputs, output) - output.value, err = - parser.parseInitializationValues(1) - into.outputs = append(into.outputs, output) - if err != nil { return } - } else { - output.value, err = - parser.parseArgument() - into.outputs = append(into.outputs, output) - if err != nil { return } - - err = parser.expect(lexer.TokenKindNewline) - if err != nil { return } - err = parser.nextToken() - if err != nil { return } - } + parser.expect(lexer.TokenKindNewline) + if err != nil { return } + err = parser.nextToken() + if err != nil { return } } } } diff --git a/parser/func_test.go b/parser/func_test.go index 99facdf..e44e528 100644 --- a/parser/func_test.go +++ b/parser/func_test.go @@ -8,13 +8,13 @@ func TestFunc (test *testing.T) { --- func ro aBasicExternal > someInput:Int:mut - < someOutput:Int 4 + < someOutput:Int:<4> --- external func ro bMethod @ bird:{Bird} > someInput:Int:mut - < someOutput:Int 4 + < someOutput:Int:<4> --- external func ro cBasicPhrases @@ -101,20 +101,9 @@ func ro gControlFlow [otherThing] func ro hSetPhrase --- - [= x:Int 3] - [= y:{Int} [loc x]] - [= z:Int:8] - 398 - 9 - 2309 - 983 - -2387 - 478 - 555 - 123 - [= bird:Bird] - .that - .whenYou 99999 - .this 324 + [let x:Int:<3>] + [let y:{Int}:<[loc x]>] + [let z:Int:8:<398 9 2309 983 -2387 478 555 123>] + [let bird:Bird:(.that:(.whenYou:<99999>) .this:<324>)] `, test) } diff --git a/parser/initialization-values.go b/parser/initialization-values.go deleted file mode 100644 index 58e4ed5..0000000 --- a/parser/initialization-values.go +++ /dev/null @@ -1,170 +0,0 @@ -package parser - -import "git.tebibyte.media/arf/arf/lexer" -import "git.tebibyte.media/arf/arf/infoerr" - -// parseInitializationValues starts on the line after a data section, or a set -// phrase. It checks for an indent greater than the indent of the aforementioned -// data section or set phrase (passed through baseIndent), and if there is, -// it parses initialization values. -func (parser *ParsingOperation) parseInitializationValues ( - baseIndent int, -) ( - initializationArgument Argument, - err error, -) { - // check if line is indented one more than baseIndent - if !parser.token.Is(lexer.TokenKindIndent) { return } - if parser.token.Value().(int) != baseIndent + 1 { return } - - initializationArgument.location = parser.token.Location() - - err = parser.nextToken() - if err != nil { return } - - if parser.token.Is(lexer.TokenKindDot) { - - // object initialization - parser.previousToken() - var initializationValues ObjectInitializationValues - initializationValues, err = parser.parseObjectInitializationValues() - initializationArgument.kind = ArgumentKindObjectInitializationValues - initializationArgument.value = initializationValues - - } else { - - // array initialization - parser.previousToken() - var initializationValues ArrayInitializationValues - initializationValues, err = parser.parseArrayInitializationValues() - initializationArgument.kind = ArgumentKindArrayInitializationValues - initializationArgument.value = initializationValues - } - - return -} - -// parseObjectInitializationValues parses a list of object initialization -// values until the indentation level drops. -func (parser *ParsingOperation) parseObjectInitializationValues () ( - initializationValues ObjectInitializationValues, - err error, -) { - initializationValues.attributes = make(map[string] Argument) - - baseIndent := 0 - begin := true - - for { - // if there is no indent we can just stop parsing - if !parser.token.Is(lexer.TokenKindIndent) { break} - indent := parser.token.Value().(int) - - if begin == true { - initializationValues.location = parser.token.Location() - baseIndent = indent - begin = false - } - - // do not parse any further if the indent has changed - if indent != baseIndent { break } - - // move on to the beginning of the line, which must contain - // a member initialization value - err = parser.nextToken(lexer.TokenKindDot) - if err != nil { return } - err = parser.nextToken(lexer.TokenKindName) - if err != nil { return } - name := parser.token.Value().(string) - - // if the member has already been listed, throw an error - _, exists := initializationValues.attributes[name] - if exists { - err = parser.token.NewError ( - "duplicate member \"" + name + "\" in object " + - "member initialization", - infoerr.ErrorKindError) - return - } - - // parse the argument determining the member initialization - // value - err = parser.nextToken() - if err != nil { return } - var value Argument - if parser.token.Is(lexer.TokenKindNewline) { - - // recurse - err = parser.nextToken(lexer.TokenKindIndent) - if err != nil { return } - - value, err = parser.parseInitializationValues(baseIndent) - initializationValues.attributes[name] = value - if err != nil { return } - - } else { - - // parse as normal argument - value, err = parser.parseArgument() - initializationValues.attributes[name] = value - if err != nil { return } - - err = parser.expect(lexer.TokenKindNewline) - if err != nil { return } - err = parser.nextToken() - if err != nil { return } - } - } - - return -} - -// parseArrayInitializationValues parses a list of array initialization values -// until the indentation lexel drops. -func (parser *ParsingOperation) parseArrayInitializationValues () ( - initializationValues ArrayInitializationValues, - err error, -) { - baseIndent := 0 - begin := true - - for { - // if there is no indent we can just stop parsing - if !parser.token.Is(lexer.TokenKindIndent) { break} - indent := parser.token.Value().(int) - - if begin == true { - initializationValues.location = parser.token.Location() - baseIndent = indent - begin = false - } - - // do not parse any further if the indent has changed - if indent != baseIndent { break } - - // move on to the beginning of the line, which must contain - // arguments - err = parser.nextToken(validArgumentStartTokens...) - if err != nil { return } - - for { - // stop parsing this line and go on to the next if a - // newline token is encountered - if parser.token.Is(lexer.TokenKindNewline) { - err = parser.nextToken() - if err != nil { return } - break - } - - // otherwise, parse the argument - var argument Argument - argument, err = parser.parseArgument() - if err != nil { return } - initializationValues.values = append ( - initializationValues.values, - argument) - } - } - - return -} diff --git a/parser/meta_test.go b/parser/meta_test.go index 26af856..467135f 100644 --- a/parser/meta_test.go +++ b/parser/meta_test.go @@ -12,7 +12,7 @@ author "Sasha Koshka" license "GPLv3" require "` + filepath.Join(cwd, "./some/local/module") + `" require "/some/absolute/path/to/someModule" -require "/usr/include/arf/someLibraryInstalledInStandardLocation" +require "/usr/local/include/arf/someLibraryInstalledInStandardLocation" --- `, test) } diff --git a/parser/misc.go b/parser/misc.go index 52b3879..ebe2e00 100644 --- a/parser/misc.go +++ b/parser/misc.go @@ -1,74 +1,6 @@ package parser import "git.tebibyte.media/arf/arf/lexer" -import "git.tebibyte.media/arf/arf/infoerr" - -// parseType parses a type notation of the form Name, {Name}, etc. -func (parser *ParsingOperation) parseType () (what Type, err error) { - err = parser.expect(lexer.TokenKindName, lexer.TokenKindLBrace) - if err != nil { return } - what.location = parser.token.Location() - - if parser.token.Is(lexer.TokenKindLBrace) { - what.kind = TypeKindPointer - - err = parser.nextToken() - if err != nil { return } - - var points Type - points, err = parser.parseType() - if err != nil { return } - what.points = &points - - err = parser.expect ( - lexer.TokenKindRBrace, - lexer.TokenKindElipsis) - if err != nil { return } - - if parser.token.Is(lexer.TokenKindElipsis) { - what.kind = TypeKindVariableArray - - err = parser.nextToken(lexer.TokenKindRBrace) - if err != nil { return } - } - - err = parser.nextToken() - if err != nil { return } - } else { - what.name, err = parser.parseIdentifier() - if err != nil { return } - } - - for { - if !parser.token.Is(lexer.TokenKindColon) { break } - - err = parser.nextToken(lexer.TokenKindName, lexer.TokenKindUInt) - if err != nil { return } - - if parser.token.Is(lexer.TokenKindName) { - // parse type qualifier - qualifier := parser.token.Value().(string) - switch qualifier { - case "mut": - what.mutable = true - default: - err = parser.token.NewError ( - "unknown type qualifier \"" + - qualifier + "\"", - infoerr.ErrorKindError) - return - } - } else { - // parse fixed array length - what.length = parser.token.Value().(uint64) - } - - err = parser.nextToken() - if err != nil { return } - } - - return -} // parseIdentifier parses an identifier made out of dot separated names. func (parser *ParsingOperation) parseIdentifier () ( @@ -80,7 +12,10 @@ func (parser *ParsingOperation) parseIdentifier () ( identifier.location = parser.token.Location() for { - if !parser.token.Is(lexer.TokenKindName) { break } + if !parser.token.Is(lexer.TokenKindName) { + parser.previousToken() + break + } identifier.trail = append ( identifier.trail, diff --git a/parser/objt.go b/parser/objt.go deleted file mode 100644 index 1e83e98..0000000 --- a/parser/objt.go +++ /dev/null @@ -1,125 +0,0 @@ -package parser - -import "git.tebibyte.media/arf/arf/types" -import "git.tebibyte.media/arf/arf/lexer" -import "git.tebibyte.media/arf/arf/infoerr" - -// parseObjtSection parses an object type definition. This allows for structured -// types to be defined, and for member variables to be added and overridden. -func (parser *ParsingOperation) parseObjtSection () ( - section ObjtSection, - err error, -) { - err = parser.expect(lexer.TokenKindName) - if err != nil { return } - - section.location = parser.token.Location() - - // get permission - err = parser.nextToken(lexer.TokenKindPermission) - if err != nil { return } - section.permission = parser.token.Value().(types.Permission) - - // get name - err = parser.nextToken(lexer.TokenKindName) - if err != nil { return } - section.name = parser.token.Value().(string) - - // parse inherited type - err = parser.nextToken(lexer.TokenKindColon) - if err != nil { return } - err = parser.nextToken() - if err != nil { return } - section.inherits, err = parser.parseIdentifier() - if err != nil { return } - err = parser.expect(lexer.TokenKindNewline) - if err != nil { return } - err = parser.nextToken() - if err != nil { return } - - // parse members - err = parser.parseObjtMembers(§ion) - if err != nil { return } - - if len(section.members) == 0 { - infoerr.NewError ( - section.location, - "defining an object with no members", - infoerr.ErrorKindWarn).Print() - } - return -} - -// parseObjtMembers parses a list of members for an object section. Indentation -// level is assumed. -func (parser *ParsingOperation) parseObjtMembers ( - into *ObjtSection, -) ( - err error, -) { - for { - // if we've left the block, stop parsing - if !parser.token.Is(lexer.TokenKindIndent) { return } - if parser.token.Value().(int) != 1 { return } - - // add member to object section - var member ObjtMember - member, err = parser.parseObjtMember() - into.members = append(into.members, member) - if err != nil { return } - } -} - -// parseObjtMember parses a single member of an object section. Indentation -// level is assumed. -func (parser *ParsingOperation) parseObjtMember () ( - member ObjtMember, - err error, -) { - // get permission - err = parser.nextToken(lexer.TokenKindPermission) - if err != nil { return } - member.permission = parser.token.Value().(types.Permission) - - // get name - err = parser.nextToken(lexer.TokenKindName) - if err != nil { return } - member.name = parser.token.Value().(string) - - // get type - err = parser.nextToken(lexer.TokenKindColon) - if err != nil { return } - err = parser.nextToken() - if err != nil { return } - member.what, err = parser.parseType() - if err != nil { return } - - // if there is a bit width, get it - if parser.token.Is(lexer.TokenKindBinaryAnd) { - err = parser.nextToken(lexer.TokenKindUInt) - if err != nil { return } - member.bitWidth = parser.token.Value().(uint64) - err = parser.nextToken() - if err != nil { return } - } - - // parse default value - if parser.token.Is(lexer.TokenKindNewline) { - err = parser.nextToken() - if err != nil { return } - - member.value, - err = parser.parseInitializationValues(1) - if err != nil { return } - } else { - member.value, err = parser.parseArgument() - if err != nil { return } - - err = parser.expect(lexer.TokenKindNewline) - if err != nil { return } - err = parser.nextToken() - if err != nil { return } - } - - return -} diff --git a/parser/objt_test.go b/parser/objt_test.go deleted file mode 100644 index eda582d..0000000 --- a/parser/objt_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package parser - -import "testing" - -func TestObjt (test *testing.T) { - checkTree ("../tests/parser/objt", false, -`:arf ---- -objt ro Basic:Obj - ro that:Basic - ro this:Basic -objt ro BitFields:Obj - ro that:Int & 1 - ro this:Int & 24 298 -objt ro ComplexInit:Obj - ro whatever:Int:3 - 230984 - 849 - 394580 - ro complex0:Bird - .that 98 - .this 2 - ro complex1:Bird - .that 98902 - .this 235 - ro basic:Int 87 -objt ro Init:Obj - ro that:String "hello world" - ro this:Int 23 -`, test) -} diff --git a/parser/parser.go b/parser/parser.go index 2520af9..b64f89c 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -166,3 +166,21 @@ func (parser *ParsingOperation) skipIndentLevel (indent int) (err error) { if err != nil { return } } } + +// skipWhitespace skips over newlines and indent tokens. +func (parser *ParsingOperation) skipWhitespace () (err error) { + for { + isWhitespace := + parser.token.Is(lexer.TokenKindIndent) || + parser.token.Is(lexer.TokenKindNewline) + + if !isWhitespace { + break + } + + err = parser.nextToken() + if err != nil { return } + } + + return +} diff --git a/parser/phrase.go b/parser/phrase.go index 8864772..7db3fbd 100644 --- a/parser/phrase.go +++ b/parser/phrase.go @@ -139,25 +139,16 @@ func (parser *ParsingOperation) parseBlockLevelPhrase ( err = parser.expect(validDelimitedPhraseTokens...) if err != nil { return } + // we are delimited so we can safely skip whitespace + err = parser.skipWhitespace() + if err != nil { return } + if parser.token.Is(lexer.TokenKindRBracket) { // this is an ending delimiter err = parser.nextToken() if err != nil { return } break - } else if parser.token.Is(lexer.TokenKindNewline) { - // we are delimited, so we can safely skip - // newlines - err = parser.nextToken() - if err != nil { return } - continue - - } else if parser.token.Is(lexer.TokenKindIndent) { - // we are delimited, so we can safely skip - // indents - err = parser.nextToken() - if err != nil { return } - continue } } else { // not delimited @@ -176,7 +167,7 @@ func (parser *ParsingOperation) parseBlockLevelPhrase ( } } - // this is an argument + // if we've got this far, we are parsing an argument var argument Argument argument, err = parser.parseArgument() phrase.arguments = append(phrase.arguments, argument) @@ -213,18 +204,6 @@ func (parser *ParsingOperation) parseBlockLevelPhrase ( err = parser.nextToken() if err != nil { return } - // if this is a set phrase, parse initialization values under it - if phrase.kind == PhraseKindAssign { - var values Argument - values, err = parser.parseInitializationValues(indent) - - if values.kind != ArgumentKindNil { - phrase.arguments = append(phrase.arguments, values) - } - - return - } - // if this is a control flow phrase, parse block under it isControlFlow := false for _, kind := range controlFlowKinds { @@ -234,10 +213,9 @@ func (parser *ParsingOperation) parseBlockLevelPhrase ( } } - if !isControlFlow { return } - - // if it is any of those, parse the block under it - phrase.block, err = parser.parseBlock(indent + 1) + if isControlFlow { + phrase.block, err = parser.parseBlock(indent + 1) + } return } @@ -330,6 +308,8 @@ func (parser *ParsingOperation) parsePhraseCommand () ( identifier := command.value.(Identifier) if len(identifier.trail) == 1 { switch identifier.trail[0] { + case "let": + kind = PhraseKindLet case "loc": kind = PhraseKindReference case "defer": diff --git a/parser/tree-tostring.go b/parser/tree-tostring.go index 28c09ff..e38f6cf 100644 --- a/parser/tree-tostring.go +++ b/parser/tree-tostring.go @@ -66,12 +66,84 @@ func (identifier Identifier) ToString () (output string) { return } -func (what Type) ToString () (output string) { +func (values ObjectDefaultValues) ToString ( + indent int, + breakLine bool, +) ( + output string, +) { + if !breakLine { indent = 0 } + output += doIndent(indent, "(") + if breakLine { output += "\n" } + + for index, name := range sortMapKeysAlphabetically(values) { + if index > 0 && !breakLine { output += " " } + + value := values[name] + + output += doIndent(indent, "." + name + ":") + + isComplexDefaultValue := + value.kind == ArgumentKindObjectDefaultValues || + value.kind == ArgumentKindArrayDefaultValues + + if isComplexDefaultValue { + if breakLine { output += "\n" } + output += value.ToString(indent + 1, breakLine) + } else { + output += "<" + output += value.ToString(indent + 1, false) + output += ">" + } + if breakLine { output += "\n" } + } + output += doIndent(indent, ")") + return +} + +func (values ArrayDefaultValues) ToString ( + indent int, + breakLine bool, +) ( + output string, +) { + if !breakLine { indent = 0 } + output += doIndent(indent, "<") + if breakLine { output += "\n" } + + for index, value := range values { + if index > 0 && !breakLine { output += " " } + output += value.ToString(indent, breakLine) + } + + output += doIndent(indent, ">") + return +} + +func (member TypeMember) ToString (indent int, breakLine bool) (output string) { + output += doIndent(indent, ".") + + output += member.permission.ToString() + " " + output += member.name + ":" + output += member.what.ToString(indent + 1, breakLine) + + if member.bitWidth > 0 { + output += fmt.Sprint(" & ", member.bitWidth) + } + + if breakLine { + output += "\n" + } + + return +} + +func (what Type) ToString (indent int, breakLine bool) (output string) { if what.kind == TypeKindBasic { output += what.name.ToString() } else { output += "{" - output += what.points.ToString() + output += what.points.ToString(indent, breakLine) if what.kind == TypeKindVariableArray { output += " .." @@ -87,45 +159,46 @@ func (what Type) ToString () (output string) { if what.mutable { output += ":mut" } - - return -} -func (declaration Declaration) ToString () (output string) { - output += declaration.name + ":" - output += declaration.what.ToString() - return -} - -func (attributes ObjectInitializationValues) ToString ( - indent int, -) ( - output string, -) { - for _, name := range sortMapKeysAlphabetically(attributes.attributes) { - value := attributes.attributes[name] - - output += doIndent(indent, ".", name) - if value.kind == ArgumentKindObjectInitializationValues { - output += "\n" - output += value.ToString(indent + 1, true) + if what.members != nil { + if breakLine { + output += ":\n" + doIndent(indent, "(\n") + for _, member := range what.members { + output += member.ToString(indent, breakLine) + } + output += doIndent(indent, ")") } else { - output += " " + value.ToString(0, false) + "\n" + output += ":(" + for index, member := range what.members { + if index > 0 { output += " " } + output += member.ToString(indent, breakLine) + } + output += ")" + } + } + + defaultValueKind := what.defaultValue.kind + if defaultValueKind != ArgumentKindNil { + isComplexDefaultValue := + defaultValueKind == ArgumentKindObjectDefaultValues || + defaultValueKind == ArgumentKindArrayDefaultValues + + if isComplexDefaultValue { + output += ":" + if breakLine { output += "\n" } + output += what.defaultValue.ToString(indent, breakLine) + } else { + output += ":<" + output += what.defaultValue.ToString(indent, false) + output += ">" } } - return } -func (values ArrayInitializationValues) ToString ( - indent int, -) ( - output string, -) { - for _, value := range values.values { - output += value.ToString(indent, true) - } - +func (declaration Declaration) ToString (indent int) (output string) { + output += declaration.name + ":" + output += declaration.what.ToString(indent, false) return } @@ -143,15 +216,13 @@ func (argument Argument) ToString (indent int, breakLine bool) (output string) { indent, breakLine) - case ArgumentKindObjectInitializationValues: - // this should only appear in contexts where breakLine is true - output += argument.value.(ObjectInitializationValues). - ToString(indent) + case ArgumentKindObjectDefaultValues: + output += argument.value.(ObjectDefaultValues). + ToString(indent, breakLine) - case ArgumentKindArrayInitializationValues: - // this should only appear in contexts where breakLine is true - output += argument.value.(ArrayInitializationValues). - ToString(indent) + case ArgumentKindArrayDefaultValues: + output += argument.value.(ArrayDefaultValues). + ToString(indent, breakLine) case ArgumentKindIdentifier: output += doIndent ( @@ -162,7 +233,7 @@ func (argument Argument) ToString (indent int, breakLine bool) (output string) { case ArgumentKindDeclaration: output += doIndent ( indent, - argument.value.(Declaration).ToString()) + argument.value.(Declaration).ToString(indent)) if breakLine { output += "\n" } case ArgumentKindInt, ArgumentKindUInt, ArgumentKindFloat: @@ -260,24 +331,12 @@ func (section DataSection) ToString (indent int) (output string) { "data ", section.permission.ToString(), " ", section.name, ":", - section.what.ToString()) - - isComplexInitialization := - section.value.kind == ArgumentKindObjectInitializationValues || - section.value.kind == ArgumentKindArrayInitializationValues - + section.what.ToString(indent + 1, true), "\n") + if section.external { - output += "\n" output += doIndent(indent + 1, "external\n") - } else if section.value.value == nil { - output += "\n" - } else if isComplexInitialization { - output += "\n" - output += section.value.ToString(indent + 1, true) - } else { - output += " " + section.value.ToString(0, false) - output += "\n" } + return } @@ -287,65 +346,10 @@ func (section TypeSection) ToString (indent int) (output string) { "type ", section.permission.ToString(), " ", section.name, ":", - section.what.ToString()) - - isComplexInitialization := - section.value.kind == ArgumentKindObjectInitializationValues || - section.value.kind == ArgumentKindArrayInitializationValues - - if section.value.value == nil { - output += "\n" - } else if isComplexInitialization { - output += "\n" - output += section.value.ToString(indent + 1, true) - } else { - output += " " + section.value.ToString(0, false) - output += "\n" - } + section.what.ToString(indent + 1, true), "\n") return } -func (member ObjtMember) ToString (indent int) (output string) { - output += doIndent(indent) - - output += member.permission.ToString() + " " - output += member.name + ":" - output += member.what.ToString() - - if member.bitWidth > 0 { - output += fmt.Sprint(" & ", member.bitWidth) - } - - isComplexInitialization := - member.value.kind == ArgumentKindObjectInitializationValues || - member.value.kind == ArgumentKindArrayInitializationValues - - if member.value.value == nil { - output += "\n" - } else if isComplexInitialization { - output += "\n" - output += member.value.ToString(indent + 1, true) - } else { - output += " " + member.value.ToString(0, false) - output += "\n" - } - - return -} - -func (section ObjtSection) ToString (indent int) (output string) { - output += doIndent ( - indent, - "objt ", - section.permission.ToString(), " ", - section.name, ":", - section.inherits.ToString(), "\n") - - for _, member := range section.members { - output += member.ToString(indent + 1) - } - return -} func (section EnumSection) ToString (indent int) (output string) { output += doIndent ( @@ -353,24 +357,22 @@ func (section EnumSection) ToString (indent int) (output string) { "enum ", section.permission.ToString(), " ", section.name, ":", - section.what.ToString(), "\n") + section.what.ToString(indent + 1, true), "\n") for _, member := range section.members { - output += doIndent(indent + 1, member.name) + output += doIndent(indent + 1, "- ", member.name) isComplexInitialization := - member.value.kind == ArgumentKindObjectInitializationValues || - member.value.kind == ArgumentKindArrayInitializationValues + member.value.kind == ArgumentKindObjectDefaultValues || + member.value.kind == ArgumentKindArrayDefaultValues - if member.value.value == nil { - output += "\n" - } else if isComplexInitialization { - output += "\n" + if isComplexInitialization { + output += ":\n" output += member.value.ToString(indent + 2, true) - } else { - output += " " + member.value.ToString(0, false) - output += "\n" + } else if member.value.kind != ArgumentKindNil { + output += ":<" + member.value.ToString(0, false) + ">" } + output += "\n" } return } @@ -394,11 +396,11 @@ func (behavior FaceBehavior) ToString (indent int) (output string) { output += doIndent(indent, behavior.name, "\n") for _, inputItem := range behavior.inputs { - output += doIndent(indent + 1, "> ", inputItem.ToString(), "\n") + output += doIndent(indent + 1, "> ", inputItem.ToString(indent), "\n") } for _, outputItem := range behavior.outputs { - output += doIndent(indent + 1, "< ", outputItem.ToString(), "\n") + output += doIndent(indent + 1, "< ", outputItem.ToString(indent), "\n") } return @@ -409,18 +411,9 @@ func (phrase Phrase) ToString (indent int, ownLine bool) (output string) { output += doIndent(indent) } - var initializationValues Argument - output += "[" + phrase.command.ToString(0, false) for _, argument := range phrase.arguments { - isInitializationValue := - argument.kind == ArgumentKindObjectInitializationValues || - argument.kind == ArgumentKindArrayInitializationValues - if isInitializationValue { - initializationValues = argument - } else { - output += " " + argument.ToString(0, false) - } + output += " " + argument.ToString(0, false) } output += "]" @@ -433,10 +426,9 @@ func (phrase Phrase) ToString (indent int, ownLine bool) (output string) { if ownLine { output += "\n" - if initializationValues.kind != ArgumentKindNil { - output += initializationValues.ToString(indent + 1, true) - } output += phrase.block.ToString(indent + 1) + } else if len(phrase.block) > 0 { + output += "NON-BLOCK-LEVEL-PHRASE-HAS-BLOCK" } return } @@ -449,14 +441,6 @@ func (block Block) ToString (indent int) (output string) { return } -func (funcOutput FuncOutput) ToString () (output string) { - output += funcOutput.Declaration.ToString() - if funcOutput.value.kind != ArgumentKindNil { - output += " " + funcOutput.value.ToString(0, false) - } - return -} - func (section FuncSection) ToString (indent int) (output string) { output += doIndent ( indent, @@ -467,15 +451,15 @@ func (section FuncSection) ToString (indent int) (output string) { if section.receiver != nil { output += doIndent ( indent + 1, - "@ ", section.receiver.ToString(), "\n") + "@ ", section.receiver.ToString(indent), "\n") } for _, inputItem := range section.inputs { - output += doIndent(indent + 1, "> ", inputItem.ToString(), "\n") + output += doIndent(indent + 1, "> ", inputItem.ToString(indent), "\n") } for _, outputItem := range section.outputs { - output += doIndent(indent + 1, "< ", outputItem.ToString(), "\n") + output += doIndent(indent + 1, "< ", outputItem.ToString(indent), "\n") } output += doIndent(indent + 1, "---\n") diff --git a/parser/tree.go b/parser/tree.go index a1be9dd..3a7745a 100644 --- a/parser/tree.go +++ b/parser/tree.go @@ -20,7 +20,6 @@ type SectionKind int const ( SectionKindType = iota - SectionKindObjt SectionKindEnum SectionKindFace SectionKindData @@ -48,17 +47,27 @@ type Identifier struct { type TypeKind int const ( - // TypeKindBasic either means it's a primitive, or it inherits from - // something. + // TypeKindBasic means its a normal type and inherits from something. + // Basic types can define new members on their parent types. TypeKindBasic TypeKind = iota - // TypeKindPointer means it's a pointer + // TypeKindPointer means it's a pointer. TypeKindPointer // TypeKindVariableArray means it's an array of variable length. TypeKindVariableArray ) +// TypeMember represents a member variable of a type specifier. +type TypeMember struct { + locatable + nameable + typeable + permissionable + + bitWidth uint64 +} + // Type represents a type specifier type Type struct { locatable @@ -72,6 +81,12 @@ type Type struct { // not applicable for basic. points *Type + + // if non-nil, this type defines new members. + members []TypeMember + + // the default value of the type. + defaultValue Argument } // Declaration represents a variable declaration. @@ -81,19 +96,12 @@ type Declaration struct { typeable } -// ObjectInitializationValues represents a list of object member initialization +// ObjectDefaultValues represents a list of object member initialization // attributes. -type ObjectInitializationValues struct { - locatable - attributes map[string] Argument -} +type ObjectDefaultValues map[string] Argument -// ArrayInitializationValues represents a list of attributes initializing an -// array. -type ArrayInitializationValues struct { - locatable - values []Argument -} +// ArrayDefaultValues represents a list of elements initializing an array. +type ArrayDefaultValues []Argument // ArgumentKind specifies the type of thing the value of an argument should be // cast to. @@ -113,12 +121,12 @@ const ( // {name 23} ArgumentKindSubscript - // .name value - // but like, a lot of them - ArgumentKindObjectInitializationValues + // (.name ) + // (.name .name (.name + ArgumentKindArrayDefaultValues // name.name // name.name.name @@ -168,39 +176,16 @@ type DataSection struct { nameable typeable permissionable - valuable external bool } -// TypeSection represents a blind type definition. +// TypeSection represents a type definition. type TypeSection struct { locatable nameable typeable permissionable - valuable -} - -// ObjtMember represents a part of an object type definition. -type ObjtMember struct { - locatable - nameable - typeable - permissionable - valuable - - bitWidth uint64 -} - -// ObjtSection represents an object type definition. -type ObjtSection struct { - locatable - nameable - permissionable - inherits Identifier - - members []ObjtMember } // EnumMember represents a member of an enum section. @@ -246,6 +231,7 @@ const ( PhraseKindCall = iota PhraseKindCallExternal PhraseKindOperator + PhraseKindLet PhraseKindAssign PhraseKindReference PhraseKindDefer @@ -275,13 +261,6 @@ type Phrase struct { // Block represents a scoped/indented block of code. type Block []Phrase -// FuncOutput represents an input a function section. It is unlike an input in -// that it can have a default value. -type FuncOutput struct { - Declaration - valuable -} - // FuncSection represents a function section. type FuncSection struct { locatable @@ -290,7 +269,7 @@ type FuncSection struct { receiver *Declaration inputs []Declaration - outputs []FuncOutput + outputs []Declaration root Block external bool diff --git a/parser/type-notation.go b/parser/type-notation.go new file mode 100644 index 0000000..945a08f --- /dev/null +++ b/parser/type-notation.go @@ -0,0 +1,318 @@ +package parser + +import "git.tebibyte.media/arf/arf/lexer" +import "git.tebibyte.media/arf/arf/infoerr" +import "git.tebibyte.media/arf/arf/types" + +// parseType parses a type notation of the form Name, {Name}, etc. +func (parser *ParsingOperation) parseType () (what Type, err error) { + err = parser.expect(lexer.TokenKindName, lexer.TokenKindLBrace) + if err != nil { return } + what.location = parser.token.Location() + + if parser.token.Is(lexer.TokenKindLBrace) { + what.kind = TypeKindPointer + + err = parser.nextToken() + if err != nil { return } + + var points Type + points, err = parser.parseType() + if err != nil { return } + what.points = &points + + err = parser.expect ( + lexer.TokenKindRBrace, + lexer.TokenKindElipsis) + if err != nil { return } + + if parser.token.Is(lexer.TokenKindElipsis) { + what.kind = TypeKindVariableArray + + err = parser.nextToken(lexer.TokenKindRBrace) + if err != nil { return } + } + + err = parser.nextToken() + if err != nil { return } + } else { + what.name, err = parser.parseIdentifier() + if err != nil { return } + } + + for { + if !parser.token.Is(lexer.TokenKindColon) { break } + + err = parser.nextToken() + if err != nil { return } + err = parser.skipWhitespace() + if err != nil { return } + + err = parser.expect( + lexer.TokenKindName, + lexer.TokenKindUInt, + lexer.TokenKindLParen, + lexer.TokenKindLessThan) + if err != nil { return } + + if parser.token.Is(lexer.TokenKindName) { + // parse type qualifier + qualifier := parser.token.Value().(string) + switch qualifier { + case "mut": + what.mutable = true + default: + err = parser.token.NewError ( + "unknown type qualifier \"" + + qualifier + "\"", + infoerr.ErrorKindError) + return + } + err = parser.nextToken() + if err != nil { return } + + } else if parser.token.Is(lexer.TokenKindUInt) { + // parse fixed array length + what.length = parser.token.Value().(uint64) + err = parser.nextToken() + if err != nil { return } + + } else if parser.token.Is(lexer.TokenKindLessThan) { + // parse default value + what.defaultValue, err = parser.parseBasicDefaultValue() + if err != nil { return } + + } else if parser.token.Is(lexer.TokenKindLParen) { + // parse members and member default values + what.defaultValue, + what.members, + err = parser.parseObjectDefaultValueAndMembers() + if err != nil { return } + } + } + + return +} + +// parseBasicDefaultValue parses a default value of a non-object type. +func (parser *ParsingOperation) parseBasicDefaultValue () ( + value Argument, + err error, +) { + value.location = parser.token.Location() + + err = parser.expect(lexer.TokenKindLessThan) + if err != nil { return } + err = parser.nextToken() + if err != nil { return } + + var attributes []Argument + + defer func () { + // if we have multiple values, we need to return the full array + // instead. + if len(attributes) > 1 { + value.kind = ArgumentKindArrayDefaultValues + value.value = ArrayDefaultValues(attributes) + } + } () + + for { + err = parser.skipWhitespace() + if err != nil { return } + if parser.token.Is(lexer.TokenKindGreaterThan) { break } + + value, err = parser.parseArgument() + if err != nil { return } + attributes = append(attributes, value) + } + + err = parser.nextToken() + if err != nil { return } + + return +} + +// parseObjectDefaultValueAndMembers parses default values and new members of an +// object type. +func (parser *ParsingOperation) parseObjectDefaultValueAndMembers () ( + value Argument, + members []TypeMember, + err error, +) { + value.location = parser.token.Location() + + err = parser.expect(lexer.TokenKindLParen) + if err != nil { return } + parser.nextToken() + if err != nil { return } + + var attributes ObjectDefaultValues + + for { + err = parser.skipWhitespace() + if err != nil { return } + if parser.token.Is(lexer.TokenKindRParen) { break } + + err = parser.expect(lexer.TokenKindDot) + if err != nil { return } + parser.nextToken(lexer.TokenKindName, lexer.TokenKindPermission) + if err != nil { return } + + if parser.token.Is(lexer.TokenKindName) { + // parsing a defalut value for an inherited member + var memberName string + var memberValue Argument + + memberName, + memberValue, err = parser.parseObjectInheritedMember() + if err != nil { return } + + if value.kind == ArgumentKindNil { + // create default value map if it doesn't + // already exist + value.kind = ArgumentKindObjectDefaultValues + attributes = make(ObjectDefaultValues) + value.value = attributes + } + + // TODO: error on duplicate + if memberValue.kind != ArgumentKindNil { + attributes[memberName] = memberValue + } + + } else if parser.token.Is(lexer.TokenKindPermission) { + // parsing a member declaration + var member TypeMember + member, err = parser.parseObjectNewMember() + + // TODO: error on duplicate + members = append(members, member) + if err != nil { return } + } + } + + err = parser.nextToken() + if err != nil { return } + + return +} + +// parseObjectDefaultValue parses member default values only, and will throw an +// error when it encounteres a new member definition. +func (parser *ParsingOperation) parseObjectDefaultValue () ( + value Argument, + err error, +) { + value.location = parser.token.Location() + + err = parser.expect(lexer.TokenKindLParen) + if err != nil { return } + parser.nextToken() + if err != nil { return } + + var attributes ObjectDefaultValues + + for { + err = parser.skipWhitespace() + if err != nil { return } + if parser.token.Is(lexer.TokenKindRParen) { break } + + err = parser.expect(lexer.TokenKindDot) + if err != nil { return } + parser.nextToken(lexer.TokenKindName) + if err != nil { return } + + if value.kind == ArgumentKindNil { + value.kind = ArgumentKindObjectDefaultValues + attributes = make(ObjectDefaultValues) + value.value = attributes + } + + var memberName string + var memberValue Argument + memberName, + memberValue, err = parser.parseObjectInheritedMember() + + attributes[memberName] = memberValue + } + + err = parser.nextToken() + if err != nil { return } + + return +} + +// .name: + +// parseObjectInheritedMember parses a new default value for an inherited +// member. +func (parser *ParsingOperation) parseObjectInheritedMember () ( + name string, + value Argument, + err error, +) { + // get the name of the inherited member + err = parser.expect(lexer.TokenKindName) + value.location = parser.token.Location() + if err != nil { return } + name = parser.token.Value().(string) + + // we require a default value to be present + err = parser.nextToken(lexer.TokenKindColon) + if err != nil { return } + err = parser.nextToken(lexer.TokenKindLParen, lexer.TokenKindLessThan) + if err != nil { return } + + if parser.token.Is(lexer.TokenKindLessThan) { + // parse default value + value, err = parser.parseBasicDefaultValue() + if err != nil { return } + + } else if parser.token.Is(lexer.TokenKindLParen) { + // parse member default values + value, err = parser.parseObjectDefaultValue() + if err != nil { return } + } + + return +} + +// .ro name:Type:qualifier: + +// parseObjectNewMember parses an object member declaration, and its +// default value if it exists. +func (parser *ParsingOperation) parseObjectNewMember () ( + member TypeMember, + err error, +) { + // get member permission + err = parser.expect(lexer.TokenKindPermission) + member.location = parser.token.Location() + if err != nil { return } + member.permission = parser.token.Value().(types.Permission) + + // get member name + err = parser.nextToken(lexer.TokenKindName) + if err != nil { return } + member.name = parser.token.Value().(string) + + // get type + err = parser.nextToken(lexer.TokenKindColon) + if err != nil { return } + err = parser.nextToken(lexer.TokenKindName, lexer.TokenKindLBrace) + if err != nil { return } + member.what, err = parser.parseType() + if err != nil { return } + + // get bit width + if parser.token.Is(lexer.TokenKindBinaryAnd) { + err = parser.nextToken(lexer.TokenKindUInt) + if err != nil { return } + member.bitWidth = parser.token.Value().(uint64) + err = parser.nextToken() + if err != nil { return } + } + + return +} diff --git a/parser/type.go b/parser/type.go index 309e543..14c8aa6 100644 --- a/parser/type.go +++ b/parser/type.go @@ -32,21 +32,10 @@ func (parser *ParsingOperation) parseTypeSection () ( section.what, err = parser.parseType() if err != nil { return } - // parse default values - if parser.token.Is(lexer.TokenKindNewline) { - err = parser.nextToken() - if err != nil { return } - - section.value, err = parser.parseInitializationValues(0) - if err != nil { return } - } else { - section.value, err = parser.parseArgument() - if err != nil { return } - - err = parser.expect(lexer.TokenKindNewline) - if err != nil { return } - err = parser.nextToken() - if err != nil { return } - } + parser.expect(lexer.TokenKindNewline) + if err != nil { return } + err = parser.nextToken() + if err != nil { return } + return } diff --git a/parser/type_test.go b/parser/type_test.go index db05b06..9863344 100644 --- a/parser/type_test.go +++ b/parser/type_test.go @@ -6,12 +6,55 @@ func TestType (test *testing.T) { checkTree ("../tests/parser/type", false, `:arf --- -type ro Basic:Int -type ro BasicInit:Int 6 -type ro IntArray:{Int ..} -type ro IntArrayInit:Int:3 +type ro aBasic:Obj: + ( + .ro that:Int + .ro this:Int + ) +type ro bBitFields:Obj: + ( + .ro that:Int & 1 + .ro this:Int:<298> & 24 + ) +type ro cInit:Obj: + ( + .ro that:String:<"hello world"> + .ro this:Int:<23> + ) +type ro dInitInherit:aBasic: + ( + .that:<9384> + .this:<389> + ) +type ro eInitAndDefine:aBasic: + ( + .ro these:aBasic: + ( + .ro born:Int:<4> + .ro in:Int + .ro the:Int:3: + < + 9348 + 92384 + 92834 + > + ): + ( + .this:<98> + ) + ): + ( + .that:<9384> + .this:<389> + ) +type ro fBasic:Int +type ro gBasicInit:Int:<6> +type ro hIntArray:{Int ..} +type ro iIntArrayInit:Int:3: + < 3298 923 92 + > `, test) } diff --git a/tests/lexer/all.arf b/tests/lexer/all.arf index aeacf53..950ece0 100644 --- a/tests/lexer/all.arf +++ b/tests/lexer/all.arf @@ -1,3 +1,3 @@ :arf ---- rw -> -349820394 932748397 239485.37520 "hello world!\n" 'E' helloWorld:.,..[]{} +--- rw -> -349820394 932748397 239485.37520 "hello world!\n" 'E' helloWorld:.,..()[]{} + - ++ -- * / @ ! % %= ~ ~= = == != < <= << <<= > >= >> >>= | |= || & &= && ^ ^= diff --git a/tests/parser/data/main.arf b/tests/parser/data/main.arf index 55833af..824cacd 100644 --- a/tests/parser/data/main.arf +++ b/tests/parser/data/main.arf @@ -1,9 +1,9 @@ :arf --- -data ro aInteger:Int 3202 +data ro aInteger:Int:<3202> -data ro bMutInteger:Int:mut 3202 +data ro bMutInteger:Int:mut:<3202> data ro cIntegerPointer:{Int} @@ -13,34 +13,33 @@ data ro eIntegerArray16:Int:16 data ro fIntegerArrayVariable:{Int ..} -data ro gIntegerArrayInitialized:Int:16 +data ro gIntegerArrayInitialized:Int:16:< 3948 293 293049 948 912 340 0 2304 0 4785 92 + > -# TODO: reinstate these two after phrase parsing is implemented -# data wr hIntegerPointerInit:{Int} [& integer] +data rw hIntegerPointerInit:{Int}:<[& integer]> -# data wr iMutIntegerPointerInit:{Int}:mut [& integer] +data rw iMutIntegerPointerInit:{Int}:mut:<[& integer]> -# TODO: maybe test identifiers somewhere else? -data ro jObject:thing.Thing. - thing.thing - .this 324 - .that 2139 +data ro jObject:Obj:( + .this:<324> + .that:<324>) -data ro kNestedObject:Obj - .this - .bird0 324 - .bird1 "hello world" - .that - .bird2 123.8439 - .bird3 9328.21348239 +data ro kNestedObject:Obj:( + .this:( + .bird0:<324> + .bird1:<"hello world">) + .ro newMember:Int:<9023> + .that:( + .bird2:<123.8439> + .bird3:<9328.21348239>)) data ro lMutIntegerArray16:Int:16:mut data ro mExternalData:Int:8 external -data ro nIntegerArrayInitialized:Int:16:mut - 3948 293 293049 948 912 - 340 0 2304 0 4785 92 +data ro nIntegerArrayInitialized:Int:16:mut: + <3948 293 293049 948 912 + 340 0 2304 0 4785 92> diff --git a/tests/parser/enum/main.arf b/tests/parser/enum/main.arf index 6d2788e..9e2aedf 100644 --- a/tests/parser/enum/main.arf +++ b/tests/parser/enum/main.arf @@ -2,29 +2,35 @@ --- enum ro Weekday:Int - sunday - monday - tuesday - wednesday - thursday - friday - saturday + - sunday + - monday + - tuesday + - wednesday + - thursday + - friday + - saturday enum ro NamedColor:U32 - red 0xFF0000 - green 0x00FF00 - blue 0x0000FF + - red: <0xFF0000> + - green: <0x00FF00> + - blue: <0x0000FF> enum ro AffrontToGod:Int:4 - bird0 - 28394 9328 - 398 9 - bird1 - 23 932832 + - bird0: + <28394 9328 + 398 9> + - bird1: + <23 932832 398 - 2349 - bird2 - 1 + 2349> + - bird2: + <1 2 3 - 4 + 4> + +enum ro ThisIsTerrible:Obj:(.rw x:Int .rw y:Int) + - up: (.x:< 0> .y:<-1>) + - down: (.x:< 0> .y:< 1>) + - left: (.x:<-1> .y:< 0>) + - right: (.x:< 1> .y:< 0>) diff --git a/tests/parser/func/main.arf b/tests/parser/func/main.arf index 79ab114..adee836 100644 --- a/tests/parser/func/main.arf +++ b/tests/parser/func/main.arf @@ -2,14 +2,14 @@ --- func ro aBasicExternal > someInput:Int:mut - < someOutput:Int 4 + < someOutput:Int:<4> --- external func ro bMethod @ bird:{Bird} > someInput:Int:mut - < someOutput:Int 4 + < someOutput:Int:<4> --- external @@ -124,13 +124,12 @@ func ro gControlFlow func ro hSetPhrase --- - = x:Int 3 + let x:Int:<3> # loc is a reference, similar to * in C - = y:{Int} [loc x] - = z:Int:8 - 398 9 2309 983 -2387 - 478 555 123 - = bird:Bird - .that - .whenYou 99999 - .this 324 + let y:{Int}:<[loc x]> + let z:Int:8: + <398 9 2309 983 -2387 + 478 555 123> + let bird:Bird:( + .that:(.whenYou:<99999>) + .this:<324>) diff --git a/tests/parser/objt/main.arf b/tests/parser/objt/main.arf deleted file mode 100644 index 9026d29..0000000 --- a/tests/parser/objt/main.arf +++ /dev/null @@ -1,25 +0,0 @@ -:arf ---- -objt ro Basic:Obj - ro that:Basic - ro this:Basic - -objt ro BitFields:Obj - ro that:Int & 1 - ro this:Int & 24 298 - -objt ro Init:Obj - ro that:String "hello world" - ro this:Int 23 - -objt ro ComplexInit:Obj - ro whatever:Int:3 - 230984 - 849 394580 - ro complex0:Bird - .that 98 - .this 2 - ro complex1:Bird - .that 98902 - .this 235 - ro basic:Int 87 diff --git a/tests/parser/skim/main.arf b/tests/parser/skim/main.arf index eefef04..762a451 100644 --- a/tests/parser/skim/main.arf +++ b/tests/parser/skim/main.arf @@ -7,12 +7,12 @@ data ro aExternalData:Int data ro bSingleValue:Int 342 data ro cNestedObject:Obj - .this - .bird0 324 - .bird1 "hello world" - .that - .bird2 123.8439 - .bird3 9328.21348239 + -- this + -- bird0 324 + -- bird1 "hello world" + -- that + -- bird2 123.8439 + -- bird3 9328.21348239 data ro dUninitialized:Int:16:mut @@ -28,9 +28,9 @@ func ro fComplexFunction 398 9 2309 983 -2387 478 555 123 = bird:Bird - .that - .whenYou 99999 - .this 324 + -- that + -- whenYou 99999 + -- this 324 func ro gExternalFunction > x:Int diff --git a/tests/parser/type/main.arf b/tests/parser/type/main.arf index 7c84c2a..8ffe9df 100644 --- a/tests/parser/type/main.arf +++ b/tests/parser/type/main.arf @@ -1,10 +1,35 @@ :arf --- -type ro Basic:Int +type ro aBasic:Obj:( + .ro that:Int + .ro this:Int) -type ro BasicInit:Int 6 +type ro bBitFields:Obj:( + .ro that:Int & 1 + .ro this:Int:<298> & 24) -type ro IntArray:{Int ..} +type ro cInit:Obj:( + .ro that:String:<"hello world"> + .ro this:Int:<23>) -type ro IntArrayInit:Int:3 - 3298 923 92 +type ro dInitInherit:aBasic:( + .that:<9384> + .this:<389>) + +type ro eInitAndDefine:aBasic:( + .this:<389> + .ro these:aBasic:( + .ro born:Int:<4> + .ro in:Int + .ro the:Int:3:<9348 92384 92834> + .this:<98>) + .that:<9384>) + +type ro fBasic:Int + +type ro gBasicInit:Int:<6> + +type ro hIntArray:{Int ..} + +type ro iIntArrayInit:Int:3: + <3298 923 92>