diff --git a/analyzer/argument.go b/analyzer/argument.go index b9f5707..5537f03 100644 --- a/analyzer/argument.go +++ b/analyzer/argument.go @@ -29,33 +29,49 @@ func (analyzer AnalysisOperation) analyzeArgument ( ) { switch inputArgument.Kind() { case parser.ArgumentKindNil: + panic ( + "invalid state: attempt to analyze nil argument") case parser.ArgumentKindPhrase: + // TODO case parser.ArgumentKindDereference: + // TODO case parser.ArgumentKindSubscript: + // TODO case parser.ArgumentKindObjectDefaultValues: + // TODO case parser.ArgumentKindArrayDefaultValues: + // TODO case parser.ArgumentKindIdentifier: + // TODO case parser.ArgumentKindDeclaration: + // TODO case parser.ArgumentKindInt: + outputArgument = IntLiteral(inputArgument.Value().(int64)) case parser.ArgumentKindUInt: + outputArgument = UIntLiteral(inputArgument.Value().(uint64)) case parser.ArgumentKindFloat: + outputArgument = FloatLiteral(inputArgument.Value().(float64)) case parser.ArgumentKindString: + outputArgument = StringLiteral(inputArgument.Value().(string)) case parser.ArgumentKindRune: + outputArgument = RuneLiteral(inputArgument.Value().(rune)) case parser.ArgumentKindOperator: - + panic ( + "invalid state: attempt to analyze operator argument " + + "directly") } return } diff --git a/parser/accessors.go b/parser/accessors.go index 1801312..f4dd4e1 100644 --- a/parser/accessors.go +++ b/parser/accessors.go @@ -82,22 +82,22 @@ func (what Type) Points () (points Type) { return } -// MembersLength returns the amount of new members the type specifier defines. +// MembersLength returns the amount of new members the type section defines. // If it defines no new members, it returns zero. -func (what Type) MembersLength () (length int) { - length = len(what.members) +func (section TypeSection) MembersLength () (length int) { + length = len(section.members) return } // Member returns the member at index. -func (what Type) Member (index int) (member TypeMember) { - member = what.members[index] +func (section TypeSection) Member (index int) (member TypeSectionMember) { + member = section.members[index] return } // 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) { +func (member TypeSectionMember) BitWidth () (width uint64) { width = member.bitWidth return } @@ -169,18 +169,6 @@ func (phrase Phrase) Kind () (kind PhraseKind) { return } -// ArgumentsLength returns the amount of arguments in the phrase. -func (phrase Phrase) ArgumentsLength () (length int) { - length = len(phrase.arguments) - return -} - -// Argument returns the argument at index. -func (phrase Phrase) Argument (index int) (argument Argument) { - argument = phrase.arguments[index] - return -} - // ReturneesLength returns the amount of things the phrase returns to. func (phrase Phrase) ReturneesLength () (length int) { length = len(phrase.returnees) diff --git a/parser/argument.go b/parser/argument.go index e821322..5332e2b 100644 --- a/parser/argument.go +++ b/parser/argument.go @@ -3,6 +3,8 @@ package parser import "git.tebibyte.media/arf/arf/lexer" import "git.tebibyte.media/arf/arf/infoerr" +// TODO: add support for dereferences and subscripts + var validArgumentStartTokens = []lexer.TokenKind { lexer.TokenKindName, @@ -13,6 +15,7 @@ var validArgumentStartTokens = []lexer.TokenKind { lexer.TokenKindRune, lexer.TokenKindLBracket, + lexer.TokenKindLParen, } func (parser *ParsingOperation) parseArgument () (argument Argument, err error) { @@ -84,6 +87,10 @@ func (parser *ParsingOperation) parseArgument () (argument Argument, err error) argument.kind = ArgumentKindPhrase argument.value, err = parser.parseArgumentLevelPhrase() + case lexer.TokenKindLParen: + argument.kind = ArgumentKindList + argument.value, err = parser.parseList() + default: panic ( "unimplemented argument kind " + diff --git a/parser/data.go b/parser/data.go index 313a909..0b0f0f3 100644 --- a/parser/data.go +++ b/parser/data.go @@ -35,28 +35,37 @@ func (parser *ParsingOperation) parseDataSection () ( 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 { + // see if value exists + if parser.token.Is(lexer.TokenKindNewline) { + parser.nextToken() + // if we have exited the section, return + if !parser.token.Is(lexer.TokenKindIndent) { return } + if parser.token.Value().(int) != 1 { return } - err = parser.nextToken(lexer.TokenKindName) + err = parser.nextToken() if err != nil { return } + } + + // check if external + if parser.token.Is(lexer.TokenKindName) { if parser.token.Value().(string) == "external" { - section.external = true + err = parser.nextToken(lexer.TokenKindNewline) - if err != nil { return } + if err != nil { return } err = parser.nextToken() if err != nil { return } return } - - parser.previousToken() } + + // get value + section.argument, err = parser.parseArgument() + 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 30739c1..d6155a4 100644 --- a/parser/data_test.go +++ b/parser/data_test.go @@ -6,14 +6,16 @@ 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 @@ -25,35 +27,21 @@ data ro gIntegerArrayInitialized:Int:16: 0 4785 92 - > -data rw hIntegerPointerInit:{Int}:<[& integer]> -data rw iMutIntegerPointerInit:{Int}:mut:<[& integer]> -data ro jObject:Obj: - ( - .that:<324> - .this:<324> ) -data ro kNestedObject:Obj: +data rw hIntegerPointerInit:{Int} + [& integer] +data rw iMutIntegerPointerInit:{Int}:mut + [& integer] +data ro jObject:Obj ( - .ro newMember:Int:<9023> - ): - ( - .that: - ( - .bird2:<123.8439> - .bird3:<9328.21348239> - ) - .this: - ( - .bird0:<324> - .bird1:<"hello world"> - ) + 324 + 438 ) 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 @@ -65,6 +53,6 @@ data ro nIntegerArrayInitialized:Int:16:mut: 0 4785 92 - > + ) `, test) } diff --git a/parser/enum.go b/parser/enum.go index c2427d9..4460941 100644 --- a/parser/enum.go +++ b/parser/enum.go @@ -61,18 +61,11 @@ 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 } - 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 } - err = parser.nextToken() - if err != nil { return } } } @@ -81,7 +74,7 @@ func (parser *ParsingOperation) parseEnumMember () ( member EnumMember, err error, ) { - err = parser.expect(lexer.TokenKindMinus) + err = parser.nextToken(lexer.TokenKindMinus) if err != nil { return } // get name @@ -91,32 +84,25 @@ func (parser *ParsingOperation) parseEnumMember () ( member.name = parser.token.Value().(string) // see if value exists - err = parser.nextToken ( - lexer.TokenKindColon, - lexer.TokenKindNewline) + err = parser.nextToken() if err != nil { return } - - if parser.token.Is(lexer.TokenKindColon) { + if parser.token.Is(lexer.TokenKindNewline) { + parser.nextToken() + // if we have exited the member, return + if !parser.token.Is(lexer.TokenKindIndent) { return } + if parser.token.Value().(int) != 2 { return } + 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 } - - } else if parser.token.Is(lexer.TokenKindLParen) { - // parse default values - member.value, err = parser.parseObjectDefaultValue() - if err != nil { return } - } } + // get value + member.argument, err = parser.parseArgument() + err = parser.expect(lexer.TokenKindNewline) + if err != nil { return } + + err = parser.nextToken() + if err != nil { return } + return } diff --git a/parser/enum_test.go b/parser/enum_test.go index 74c59b7..2fa0672 100644 --- a/parser/enum_test.go +++ b/parser/enum_test.go @@ -7,56 +7,18 @@ func TestEnum (test *testing.T) { `:arf --- enum ro AffrontToGod:Int:4 - - bird0: - < - 28394 - 9328 - 398 - 9 - > - - bird1: - < - 23 - 932832 - 398 - 2349 - > - - bird2: - < - 1 - 2 - 3 - 4 - > + - bird0 (28394 9328 398 9) + - bird1 (23 932832 398 2349) + - bird2 (1 2 3 4) enum ro NamedColor:U32 - - 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> - ) + - red 16711680 + - green 65280 + - blue 255 +enum ro ThisIsTerrible:Vector + - up (0 -1) + - down (0 1) + - left (-1 0) + - right (1 0) enum ro Weekday:Int - sunday - monday diff --git a/parser/face.go b/parser/face.go index 62f2605..80368e7 100644 --- a/parser/face.go +++ b/parser/face.go @@ -12,8 +12,7 @@ func (parser *ParsingOperation) parseFaceSection () ( err = parser.expect(lexer.TokenKindName) if err != nil { return } - section.behaviors = make(map[string] FaceBehavior) - section.location = parser.token.Location() + section.location = parser.token.Location() // get permission err = parser.nextToken(lexer.TokenKindPermission) @@ -32,24 +31,61 @@ func (parser *ParsingOperation) parseFaceSection () ( if err != nil { return } section.inherits, err = parser.parseIdentifier() if err != nil { return } - err = parser.nextToken(lexer.TokenKindNewline) + err = parser.expect(lexer.TokenKindNewline) if err != nil { return } err = parser.nextToken() if err != nil { return } + + if !parser.token.Is(lexer.TokenKindIndent) { return } + if parser.token.Value().(int) != 1 { return } + err = parser.nextToken ( + lexer.TokenKindName, + lexer.TokenKindGreaterThan, + lexer.TokenKindLessThan) + if err != nil { return } + + if parser.token.Is(lexer.TokenKindName) { + // parse type interface + section.kind = FaceKindType + parser.previousToken() + section.behaviors, err = parser.parseFaceBehaviors() + if err != nil { return } + } else { + // parse function interface + section.kind = FaceKindFunc + parser.previousToken() + section.inputs, + section.outputs, err = parser.parseFaceBehaviorArguments(1) + if err != nil { return } + } + + return +} + +// parseFaceBehaviors parses a list of interface behaviors for an object +// interface. +func (parser *ParsingOperation) parseFaceBehaviors () ( + behaviors map[string] FaceBehavior, + err error, +) { // parse members + behaviors = make(map[string] FaceBehavior) for { // if we've left the block, stop parsing if !parser.token.Is(lexer.TokenKindIndent) { return } if parser.token.Value().(int) != 1 { return } + + err = parser.nextToken(lexer.TokenKindName) + behaviorBeginning := parser.token.Location() + if err != nil { return } // parse behavior - behaviorBeginning := parser.token.Location() var behavior FaceBehavior - behavior, err = parser.parseFaceBehavior() + behavior, err = parser.parseFaceBehavior(1) // add to section - _, exists := section.behaviors[behavior.name] + _, exists := behaviors[behavior.name] if exists { err = infoerr.NewError ( behaviorBeginning, @@ -58,23 +94,21 @@ func (parser *ParsingOperation) parseFaceSection () ( infoerr.ErrorKindError) return } - section.behaviors[behavior.name] = behavior + behaviors[behavior.name] = behavior if err != nil { return } } } -// parseFaceBehavior parses a single interface behavior. Indentation level is -// assumed. -func (parser *ParsingOperation) parseFaceBehavior () ( +// parseFaceBehavior parses a single interface behavior. +func (parser *ParsingOperation) parseFaceBehavior ( + indent int, +) ( behavior FaceBehavior, err error, ) { - err = parser.expect(lexer.TokenKindIndent) - if err != nil { return } - // get name - err = parser.nextToken(lexer.TokenKindName) + err = parser.expect(lexer.TokenKindName) if err != nil { return } behavior.name = parser.token.Value().(string) @@ -82,11 +116,27 @@ func (parser *ParsingOperation) parseFaceBehavior () ( if err != nil { return } err = parser.nextToken() if err != nil { return } + + behavior.inputs, + behavior.outputs, + err = parser.parseFaceBehaviorArguments(indent + 1) + if err != nil { return } + + return +} + +func (parser *ParsingOperation) parseFaceBehaviorArguments ( + indent int, +) ( + inputs []Declaration, + outputs []Declaration, + err error, +) { for { - // if we've left the block, stop parsing + // if we've left the behavior, stop parsing if !parser.token.Is(lexer.TokenKindIndent) { return } - if parser.token.Value().(int) != 2 { return } + if parser.token.Value().(int) != indent { return } // get preceding symbol err = parser.nextToken ( @@ -109,19 +159,16 @@ func (parser *ParsingOperation) parseFaceBehavior () ( if err != nil { return } declaration.what, err = parser.parseType() if err != nil { return } + + if kind == lexer.TokenKindGreaterThan { + inputs = append(inputs, declaration) + } else { + outputs = append(outputs, declaration) + } + err = parser.expect(lexer.TokenKindNewline) if err != nil { return } err = parser.nextToken() if err != nil { return } - - if kind == lexer.TokenKindGreaterThan { - behavior.inputs = append ( - behavior.inputs, - declaration) - } else { - behavior.outputs = append ( - behavior.outputs, - declaration) - } } } diff --git a/parser/face_test.go b/parser/face_test.go new file mode 100644 index 0000000..ff38360 --- /dev/null +++ b/parser/face_test.go @@ -0,0 +1,25 @@ +package parser + +import "testing" + +func TestFace (test *testing.T) { + checkTree ("../tests/parser/face", false, +`:arf +--- +face ro aReadWriter:Face + read + > into:{Byte ..} + < read:Int + < err:Error + write + > data:{Byte ..} + < wrote:Int + < err:Error +face ro bDestroyer:Face + destroy +face ro cFuncInterface:Func + > something:Int + < someOutput:Int + < otherOutput:String +`, test) +} diff --git a/parser/func.go b/parser/func.go index 7e775c5..d7f9405 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 := Declaration { } + output := FuncOutput { } output.location = parser.token.Location() // get name @@ -186,11 +186,32 @@ func (parser *ParsingOperation) parseFuncArguments ( if err != nil { return } output.what, err = parser.parseType() if err != nil { return } - - into.outputs = append(into.outputs, output) - parser.expect(lexer.TokenKindNewline) + // skip newline if it is there + if parser.token.Is(lexer.TokenKindNewline) { + parser.nextToken() + // if we have exited the output, break + exited := + !parser.token.Is(lexer.TokenKindIndent) || + parser.token.Value().(int) != 2 + + if exited { + into.outputs = append(into.outputs, output) + break + } + + err = parser.nextToken() + if err != nil { return } + } + + // get default value + output.argument, 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 } } diff --git a/parser/func_test.go b/parser/func_test.go index e44e528..7ad00d2 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 @@ -99,11 +99,11 @@ func ro gControlFlow [nestedThing] [else] [otherThing] -func ro hSetPhrase +func ro hDataInit --- - [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>)] + [= x:Int 3] + [= y:{Int} [loc x]] + [= z:Int:8 (398 9 2309 983 -2387 478 555 123)] + [= bird:Bird ((99999) 324)] `, test) } diff --git a/parser/list.go b/parser/list.go new file mode 100644 index 0000000..3be30f9 --- /dev/null +++ b/parser/list.go @@ -0,0 +1,32 @@ +package parser + +import "git.tebibyte.media/arf/arf/lexer" + +// parseList parses a parenthetically delimited list of arguments. +func (parser *ParsingOperation) parseList () (list List, err error) { + list.location = parser.token.Location() + + err = parser.expect(lexer.TokenKindLParen) + if err != nil { return } + err = parser.nextToken() + if err != nil { return } + + for { + err = parser.skipWhitespace() + if err != nil { return } + + // if we have reached the end of the list, stop + if parser.token.Is(lexer.TokenKindRParen) { break } + + // otherwise, parse argument + var argument Argument + argument, err = parser.parseArgument() + list.arguments = append(list.arguments, argument) + if err != nil { return } + } + + err = parser.nextToken() + if err != nil { return } + + return +} diff --git a/parser/meta_test.go b/parser/meta_test.go index 467135f..07d3952 100644 --- a/parser/meta_test.go +++ b/parser/meta_test.go @@ -11,8 +11,8 @@ func TestMeta (test *testing.T) { author "Sasha Koshka" license "GPLv3" require "` + filepath.Join(cwd, "./some/local/module") + `" -require "/some/absolute/path/to/someModule" require "/usr/local/include/arf/someLibraryInstalledInStandardLocation" +require "/some/absolute/path/to/someModule" --- `, test) } diff --git a/parser/node-traits.go b/parser/node-traits.go index e16aeaf..e245882 100644 --- a/parser/node-traits.go +++ b/parser/node-traits.go @@ -10,19 +10,19 @@ type locatable struct { } // Location returns the location of the node. -func (trait locatable) Location () (location file.Location) { - location = trait.location +func (node locatable) Location () (location file.Location) { + location = node.location return } // NewError creates a new error at the node's location. -func (trait locatable) NewError ( +func (node locatable) NewError ( message string, kind infoerr.ErrorKind, ) ( err error, ) { - err = infoerr.NewError(trait.location, message, kind) + err = infoerr.NewError(node.location, message, kind) return } @@ -32,8 +32,8 @@ type nameable struct { } // Name returns the name of the node. -func (trait nameable) Name () (name string) { - name = trait.name +func (node nameable) Name () (name string) { + name = node.name return } // typeable allows a node to have a type. @@ -42,8 +42,8 @@ type typeable struct { } // Type returns the type of the node. -func (trait typeable) Type () (what Type) { - what = trait.what +func (node typeable) Type () (what Type) { + what = node.what return } @@ -53,18 +53,35 @@ type permissionable struct { } // Permission returns the permision of the node. -func (trait permissionable) Permission () (permission types.Permission) { - permission = trait.permission +func (node permissionable) Permission () (permission types.Permission) { + permission = node.permission return } // valuable allows a node to have an argument value. type valuable struct { - value Argument + argument Argument } -// Value returns the value argument of the node. -func (trait valuable) Value () (value Argument) { - value = trait.value +// Argument returns the value argument of the node. +func (node valuable) Argument () (argument Argument) { + argument = node.argument + return +} + +// multiValuable allows a node to have several argument values. +type multiValuable struct { + arguments []Argument +} + +// Argument returns the argument at index. +func (node multiValuable) Argument (index int) (argument Argument) { + argument = node.arguments[index] + return +} + +// Length returns the amount of arguments in the mode. +func (node multiValuable) Length () (length int) { + length = len(node.arguments) return } diff --git a/parser/parser.go b/parser/parser.go index b64f89c..1e54f3f 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -150,16 +150,35 @@ func (parser *ParsingOperation) previousToken () { // skipIndentLevel advances the parser, ignoring every line with an indentation // equal to or greater than the specified indent. func (parser *ParsingOperation) skipIndentLevel (indent int) (err error) { + braceLevel := 0 + parenLevel := 0 + bracketLevel := 0 + for { if parser.token.Is(lexer.TokenKindNewline) { err = parser.nextToken() if err != nil { return } - if !parser.token.Is(lexer.TokenKindIndent) || - parser.token.Value().(int) < indent { + shouldBreak := + !parser.token.Is(lexer.TokenKindIndent) || + parser.token.Value().(int) < indent + + shouldBreak = + shouldBreak && + braceLevel < 1 && + parenLevel < 1 && + bracketLevel < 1 - return - } + if shouldBreak { return } + } + + switch parser.token.Kind() { + case lexer.TokenKindLBrace: braceLevel ++ + case lexer.TokenKindRBrace: braceLevel -- + case lexer.TokenKindLParen: parenLevel ++ + case lexer.TokenKindRParen: parenLevel -- + case lexer.TokenKindLBracket: bracketLevel ++ + case lexer.TokenKindRBracket: bracketLevel -- } err = parser.nextToken() diff --git a/parser/phrase.go b/parser/phrase.go index 7db3fbd..da04024 100644 --- a/parser/phrase.go +++ b/parser/phrase.go @@ -129,7 +129,10 @@ func (parser *ParsingOperation) parseBlockLevelPhrase ( // get command err = parser.expect(validPhraseStartTokens...) if err != nil { return } - phrase.command, phrase.kind, err = parser.parsePhraseCommand() + phrase.command, + phrase.kind, + phrase.operator, + err = parser.parsePhraseCommand() if err != nil { return } for { @@ -233,7 +236,10 @@ func (parser *ParsingOperation) parseArgumentLevelPhrase () ( // get command err = parser.nextToken(validPhraseStartTokens...) if err != nil { return } - phrase.command, phrase.kind, err = parser.parsePhraseCommand() + phrase.command, + phrase.kind, + phrase.operator, + err = parser.parsePhraseCommand() if err != nil { return } for { @@ -272,24 +278,22 @@ func (parser *ParsingOperation) parseArgumentLevelPhrase () ( // parsePhraseCommand parses the command argument of a phrase. func (parser *ParsingOperation) parsePhraseCommand () ( - command Argument, - kind PhraseKind, - err error, + command Argument, + kind PhraseKind, + operator lexer.TokenKind, + err error, ) { if isTokenOperator(parser.token) { err = parser.expect(operatorTokens...) if err != nil { return } - command.location = parser.token.Location() - command.kind = ArgumentKindOperator - command.value = parser.token.Kind() - if parser.token.Is(lexer.TokenKindColon) { kind = PhraseKindCase } else if parser.token.Is(lexer.TokenKindAssignment) { kind = PhraseKindAssign } else { kind = PhraseKindOperator + operator = parser.token.Kind() } err = parser.nextToken() @@ -308,8 +312,6 @@ 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/skim_test.go b/parser/skim_test.go index 44eed97..372f0a9 100644 --- a/parser/skim_test.go +++ b/parser/skim_test.go @@ -21,7 +21,7 @@ func ro fComplexFunction external func ro gExternalFunction > x:Int - < arr:Int + < arr:Int 5 --- external `, test) diff --git a/parser/tree-tostring.go b/parser/tree-tostring.go index e38f6cf..ab75531 100644 --- a/parser/tree-tostring.go +++ b/parser/tree-tostring.go @@ -41,7 +41,8 @@ func (tree SyntaxTree) ToString (indent int) (output string) { output += doIndent(indent, "license \"", tree.license, "\"\n") } - for _, require := range tree.requires { + for _, name := range sortMapKeysAlphabetically(tree.requires) { + require := tree.requires[name] output += doIndent(indent, "require \"", require, "\"\n") } @@ -66,84 +67,17 @@ func (identifier Identifier) ToString () (output string) { return } -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) +func (what Type) ToString () (output string) { + if what.kind == TypeKindNil { + output += "NIL-TYPE" + return } - 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(indent, breakLine) + output += what.points.ToString() if what.kind == TypeKindVariableArray { output += " .." @@ -159,46 +93,27 @@ func (what Type) ToString (indent int, breakLine bool) (output string) { if what.mutable { output += ":mut" } - - 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 += ":(" - 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 (declaration Declaration) ToString (indent int) (output string) { +func (declaration Declaration) ToString () (output string) { output += declaration.name + ":" - output += declaration.what.ToString(indent, false) + output += declaration.what.ToString() + return +} + +func (list List) ToString (indent int, breakline bool) (output string) { + if !breakline { indent = 0 } + output += doIndent(indent, "(") + if breakline { output += "\n" } + + for index, argument := range list.arguments { + if !breakline && index > 0 { output += " "} + output += argument.ToString(indent, breakline) + } + + output += doIndent(indent, ")") + if breakline { output += "\n" } return } @@ -216,13 +131,8 @@ func (argument Argument) ToString (indent int, breakLine bool) (output string) { indent, breakLine) - case ArgumentKindObjectDefaultValues: - output += argument.value.(ObjectDefaultValues). - ToString(indent, breakLine) - - case ArgumentKindArrayDefaultValues: - output += argument.value.(ArrayDefaultValues). - ToString(indent, breakLine) + case ArgumentKindList: + output += argument.value.(List).ToString(indent, breakLine) case ArgumentKindIdentifier: output += doIndent ( @@ -233,7 +143,7 @@ func (argument Argument) ToString (indent int, breakLine bool) (output string) { case ArgumentKindDeclaration: output += doIndent ( indent, - argument.value.(Declaration).ToString(indent)) + argument.value.(Declaration).ToString()) if breakLine { output += "\n" } case ArgumentKindInt, ArgumentKindUInt, ArgumentKindFloat: @@ -251,75 +161,6 @@ func (argument Argument) ToString (indent int, breakLine bool) (output string) { indent, "'" + string(argument.value.(rune)) + "'") if breakLine { output += "\n" } - - case ArgumentKindOperator: - var stringValue string - switch argument.value.(lexer.TokenKind) { - case lexer.TokenKindColon: - stringValue = ":" - case lexer.TokenKindPlus: - stringValue = "+" - case lexer.TokenKindMinus: - stringValue = "-" - case lexer.TokenKindIncrement: - stringValue = "++" - case lexer.TokenKindDecrement: - stringValue = "--" - case lexer.TokenKindAsterisk: - stringValue = "*" - case lexer.TokenKindSlash: - stringValue = "/" - case lexer.TokenKindExclamation: - stringValue = "!" - case lexer.TokenKindPercent: - stringValue = "%" - case lexer.TokenKindPercentAssignment: - stringValue = "%=" - case lexer.TokenKindTilde: - stringValue = "~" - case lexer.TokenKindTildeAssignment: - stringValue = "~=" - case lexer.TokenKindAssignment: - stringValue = "=" - case lexer.TokenKindEqualTo: - stringValue = "==" - case lexer.TokenKindNotEqualTo: - stringValue = "!=" - case lexer.TokenKindLessThanEqualTo: - stringValue = "<=" - case lexer.TokenKindLessThan: - stringValue = "<" - case lexer.TokenKindLShift: - stringValue = "<<" - case lexer.TokenKindLShiftAssignment: - stringValue = "<<=" - case lexer.TokenKindGreaterThan: - stringValue = ">" - case lexer.TokenKindGreaterThanEqualTo: - stringValue = ">=" - case lexer.TokenKindRShift: - stringValue = ">>" - case lexer.TokenKindRShiftAssignment: - stringValue = ">>=" - case lexer.TokenKindBinaryOr: - stringValue = "|" - case lexer.TokenKindBinaryOrAssignment: - stringValue = "|=" - case lexer.TokenKindLogicalOr: - stringValue = "||" - case lexer.TokenKindBinaryAnd: - stringValue = "&" - case lexer.TokenKindBinaryAndAssignment: - stringValue = "&=" - case lexer.TokenKindLogicalAnd: - stringValue = "&&" - case lexer.TokenKindBinaryXor: - stringValue = "^" - case lexer.TokenKindBinaryXorAssignment: - stringValue = "^=" - } - output += doIndent(indent, stringValue) - if breakLine { output += "\n" } } return @@ -331,7 +172,11 @@ func (section DataSection) ToString (indent int) (output string) { "data ", section.permission.ToString(), " ", section.name, ":", - section.what.ToString(indent + 1, true), "\n") + section.what.ToString(), "\n") + + if section.argument.kind != ArgumentKindNil { + output += section.argument.ToString(indent + 1, true) + } if section.external { output += doIndent(indent + 1, "external\n") @@ -340,37 +185,57 @@ func (section DataSection) ToString (indent int) (output string) { return } +func (member TypeSectionMember) ToString (indent int) (output string) { + output += doIndent(indent, member.permission.ToString()) + output += " " + member.name + + if member.what.kind != TypeKindNil { + output += ":" + member.what.ToString() + } + + if member.argument.kind != ArgumentKindNil { + output += " " + member.argument.ToString(indent, false) + } + + if member.bitWidth > 0 { + output += fmt.Sprint(" & ", member.bitWidth) + } + + output += "\n" + + return +} + func (section TypeSection) ToString (indent int) (output string) { output += doIndent ( indent, "type ", section.permission.ToString(), " ", section.name, ":", - section.what.ToString(indent + 1, true), "\n") + section.what.ToString(), "\n") + + if section.argument.kind != ArgumentKindNil { + output += section.argument.ToString(indent + 1, true) + } + + for _, member := range section.members { + output += member.ToString(indent + 1) + } return } - func (section EnumSection) ToString (indent int) (output string) { output += doIndent ( indent, "enum ", section.permission.ToString(), " ", section.name, ":", - section.what.ToString(indent + 1, true), "\n") + section.what.ToString(), "\n") for _, member := range section.members { output += doIndent(indent + 1, "- ", member.name) - - isComplexInitialization := - member.value.kind == ArgumentKindObjectDefaultValues || - member.value.kind == ArgumentKindArrayDefaultValues - - if isComplexInitialization { - output += ":\n" - output += member.value.ToString(indent + 2, true) - } else if member.value.kind != ArgumentKindNil { - output += ":<" + member.value.ToString(0, false) + ">" + if member.argument.kind != ArgumentKindNil { + output += " " + member.argument.ToString(indent, false) } output += "\n" } @@ -385,10 +250,21 @@ func (section FaceSection) ToString (indent int) (output string) { section.name, ":", section.inherits.ToString(), "\n") - for _, name := range sortMapKeysAlphabetically(section.behaviors) { - behavior := section.behaviors[name] - output += behavior.ToString(indent + 1) + if section.kind == FaceKindType { + for _, name := range sortMapKeysAlphabetically(section.behaviors) { + behavior := section.behaviors[name] + output += behavior.ToString(indent + 1) + } + } else if section.kind == FaceKindFunc { + for _, inputItem := range section.inputs { + output += doIndent(indent + 1, "> ", inputItem.ToString(), "\n") + } + + for _, outputItem := range section.outputs { + output += doIndent(indent + 1, "< ", outputItem.ToString(), "\n") + } } + return } @@ -396,11 +272,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(indent), "\n") + output += doIndent(indent + 1, "> ", inputItem.ToString(), "\n") } for _, outputItem := range behavior.outputs { - output += doIndent(indent + 1, "< ", outputItem.ToString(indent), "\n") + output += doIndent(indent + 1, "< ", outputItem.ToString(), "\n") } return @@ -411,7 +287,86 @@ func (phrase Phrase) ToString (indent int, ownLine bool) (output string) { output += doIndent(indent) } - output += "[" + phrase.command.ToString(0, false) + output += "[" + + switch phrase.kind { + case PhraseKindCase: + output += ":" + + case PhraseKindAssign: + output += "=" + + case PhraseKindOperator: + + switch phrase.operator { + case lexer.TokenKindColon: + output += ":" + case lexer.TokenKindPlus: + output += "+" + case lexer.TokenKindMinus: + output += "-" + case lexer.TokenKindIncrement: + output += "++" + case lexer.TokenKindDecrement: + output += "--" + case lexer.TokenKindAsterisk: + output += "*" + case lexer.TokenKindSlash: + output += "/" + case lexer.TokenKindExclamation: + output += "!" + case lexer.TokenKindPercent: + output += "%" + case lexer.TokenKindPercentAssignment: + output += "%=" + case lexer.TokenKindTilde: + output += "~" + case lexer.TokenKindTildeAssignment: + output += "~=" + case lexer.TokenKindAssignment: + output += "=" + case lexer.TokenKindEqualTo: + output += "==" + case lexer.TokenKindNotEqualTo: + output += "!=" + case lexer.TokenKindLessThanEqualTo: + output += "<=" + case lexer.TokenKindLessThan: + output += "<" + case lexer.TokenKindLShift: + output += "<<" + case lexer.TokenKindLShiftAssignment: + output += "<<=" + case lexer.TokenKindGreaterThan: + output += ">" + case lexer.TokenKindGreaterThanEqualTo: + output += ">=" + case lexer.TokenKindRShift: + output += ">>" + case lexer.TokenKindRShiftAssignment: + output += ">>=" + case lexer.TokenKindBinaryOr: + output += "|" + case lexer.TokenKindBinaryOrAssignment: + output += "|=" + case lexer.TokenKindLogicalOr: + output += "||" + case lexer.TokenKindBinaryAnd: + output += "&" + case lexer.TokenKindBinaryAndAssignment: + output += "&=" + case lexer.TokenKindLogicalAnd: + output += "&&" + case lexer.TokenKindBinaryXor: + output += "^" + case lexer.TokenKindBinaryXorAssignment: + output += "^=" + } + + default: + output += phrase.command.ToString(0, false) + } + for _, argument := range phrase.arguments { output += " " + argument.ToString(0, false) } @@ -433,6 +388,17 @@ func (phrase Phrase) ToString (indent int, ownLine bool) (output string) { return } +func (funcOutput FuncOutput) ToString (indent int) (output string) { + output += doIndent(indent + 1) + output += "< " + funcOutput.Declaration.ToString() + if funcOutput.argument.kind != ArgumentKindNil { + output += " " + funcOutput.argument.ToString(indent, false) + } + output += "\n" + + return +} + func (block Block) ToString (indent int) (output string) { for _, phrase := range block { output += phrase.ToString(indent, true) @@ -451,15 +417,15 @@ func (section FuncSection) ToString (indent int) (output string) { if section.receiver != nil { output += doIndent ( indent + 1, - "@ ", section.receiver.ToString(indent), "\n") + "@ ", section.receiver.ToString(), "\n") } for _, inputItem := range section.inputs { - output += doIndent(indent + 1, "> ", inputItem.ToString(indent), "\n") + output += doIndent(indent + 1, "> ", inputItem.ToString(), "\n") } for _, outputItem := range section.outputs { - output += doIndent(indent + 1, "< ", outputItem.ToString(indent), "\n") + output += outputItem.ToString(indent) } output += doIndent(indent + 1, "---\n") diff --git a/parser/tree.go b/parser/tree.go index 54a62e0..f46e053 100644 --- a/parser/tree.go +++ b/parser/tree.go @@ -2,6 +2,7 @@ package parser import "git.tebibyte.media/arf/arf/file" import "git.tebibyte.media/arf/arf/types" +import "git.tebibyte.media/arf/arf/lexer" import "git.tebibyte.media/arf/arf/infoerr" // SyntaxTree represents an abstract syntax tree. It covers an entire module. It @@ -35,9 +36,12 @@ type Identifier struct { type TypeKind int const ( + // TypeKindNil means that the type is unspecified. + TypeKindNil TypeKind = iota + // TypeKindBasic means its a normal type and inherits from something. // Basic types can define new members on their parent types. - TypeKindBasic TypeKind = iota + TypeKindBasic // TypeKindPointer means it's a pointer. TypeKindPointer @@ -46,16 +50,6 @@ const ( 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 @@ -69,12 +63,6 @@ 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. @@ -84,12 +72,14 @@ type Declaration struct { typeable } -// ObjectDefaultValues represents a list of object member initialization -// attributes. -type ObjectDefaultValues map[string] Argument +// List represents an array or object literal. +type List struct { + locatable -// ArrayDefaultValues represents a list of elements initializing an array. -type ArrayDefaultValues []Argument + // TODO: have an array of unnamed arguments, and a map of named + // arguments + multiValuable +} // ArgumentKind specifies the type of thing the value of an argument should be // cast to. @@ -103,19 +93,15 @@ const ( // etc... ArgumentKindPhrase + // (argument argument argument) + ArgumentKindList + // {name} ArgumentKindDereference // {name 23} ArgumentKindSubscript - // (.name ) - // (.name .name (.name - ArgumentKindArrayDefaultValues - // name.name // name.name.name // etc... @@ -142,10 +128,6 @@ const ( // 'S' ArgumentKindRune - - // + - * / etc... - // this is only used as a phrase command - ArgumentKindOperator ) // Argument represents a value that can be placed anywhere a value goes. This @@ -164,16 +146,32 @@ type DataSection struct { nameable typeable permissionable + valuable external bool } +// TypeSectionMember represents a member variable of a type section. +type TypeSectionMember struct { + locatable + nameable + typeable + permissionable + valuable + + bitWidth uint64 +} + // TypeSection represents a type definition. type TypeSection struct { locatable nameable typeable permissionable + valuable + + // if non-nil, this type defines new members. + members []TypeSectionMember } // EnumMember represents a member of an enum section. @@ -193,6 +191,16 @@ type EnumSection struct { members []EnumMember } +// FaceKind determines if an interface is a type interface or an function +// interface. +type FaceKind int + +const ( + FaceKindEmpty FaceKind = iota + FaceKindType + FaceKindFunc +) + // FaceBehavior represents a behavior of an interface section. type FaceBehavior struct { locatable @@ -208,8 +216,11 @@ type FaceSection struct { nameable permissionable inherits Identifier - + + kind FaceKind + behaviors map[string] FaceBehavior + FaceBehavior } // PhraseKind determines what semantic role a phrase plays. @@ -219,7 +230,6 @@ const ( PhraseKindCall = iota PhraseKindCallExternal PhraseKindOperator - PhraseKindLet PhraseKindAssign PhraseKindReference PhraseKindDefer @@ -236,12 +246,18 @@ const ( // syntactical concept. type Phrase struct { location file.Location - command Argument - arguments []Argument returnees []Argument - + multiValuable + kind PhraseKind + // TODO: do not have this be an argument. make a string version, and + // and identifier version. + command Argument + + // only applicable for PhraseKindOperator + operator lexer.TokenKind + // only applicable for control flow phrases block Block } @@ -249,6 +265,13 @@ type Phrase struct { // Block represents a scoped/indented block of code. type Block []Phrase +// FuncOutput represents a function output declaration. It allows for a default +// value. +type FuncOutput struct { + Declaration + valuable +} + // FuncSection represents a function section. type FuncSection struct { locatable @@ -257,7 +280,7 @@ type FuncSection struct { receiver *Declaration inputs []Declaration - outputs []Declaration + outputs []FuncOutput root Block external bool diff --git a/parser/type-notation.go b/parser/type-notation.go index 945a08f..a03fef3 100644 --- a/parser/type-notation.go +++ b/parser/type-notation.go @@ -2,13 +2,13 @@ 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() + what.kind = TypeKindBasic if parser.token.Is(lexer.TokenKindLBrace) { what.kind = TypeKindPointer @@ -48,11 +48,7 @@ func (parser *ParsingOperation) parseType () (what Type, err error) { err = parser.skipWhitespace() if err != nil { return } - err = parser.expect( - lexer.TokenKindName, - lexer.TokenKindUInt, - lexer.TokenKindLParen, - lexer.TokenKindLessThan) + err = parser.expect(lexer.TokenKindName, lexer.TokenKindUInt) if err != nil { return } if parser.token.Is(lexer.TokenKindName) { @@ -77,242 +73,8 @@ func (parser *ParsingOperation) parseType () (what Type, err error) { 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 14c8aa6..292ec32 100644 --- a/parser/type.go +++ b/parser/type.go @@ -3,8 +3,8 @@ package parser import "git.tebibyte.media/arf/arf/types" import "git.tebibyte.media/arf/arf/lexer" -// parseTypeSection parses a blind type definition, meaning it can inherit from -// anything including primitives, but cannot define structure. +// parseTypeSection parses a type definition. It can inherit from other types, +// and define new members on them. func (parser *ParsingOperation) parseTypeSection () ( section TypeSection, err error, @@ -32,10 +32,103 @@ func (parser *ParsingOperation) parseTypeSection () ( section.what, err = parser.parseType() if err != nil { return } - parser.expect(lexer.TokenKindNewline) - if err != nil { return } - err = parser.nextToken() - if err != nil { return } + // see if value exists + if parser.token.Is(lexer.TokenKindNewline) { + parser.nextToken() + // if we have exited the section, return + if !parser.token.Is(lexer.TokenKindIndent) { return } + if parser.token.Value().(int) != 1 { return } + + err = parser.nextToken() + if err != nil { return } + } + + // if we have not encountered members, get value and return. + if !parser.token.Is(lexer.TokenKindPermission) { + section.argument, err = parser.parseArgument() + err = parser.expect(lexer.TokenKindNewline) + if err != nil { return } + + err = parser.nextToken() + if err != nil { return } + + return + } + + parser.previousToken() + + for { + // if we have exited the section, return + if !parser.token.Is(lexer.TokenKindIndent) { return } + if parser.token.Value().(int) != 1 { return } + + err = parser.nextToken(lexer.TokenKindPermission) + if err != nil { return } + var member TypeSectionMember + member, err = parser.parseTypeSectionMember() + section.members = append(section.members, member) + if err != nil { return } + } return } + +// parseTypeSectionMember parses a type section member variable. +func (parser *ParsingOperation) parseTypeSectionMember () ( + member TypeSectionMember, + err error, +) { + // get permission + err = parser.expect(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) + + // if there is a type, get it + err = parser.nextToken() + if err != nil { return } + if parser.token.Is(lexer.TokenKindColon) { + err = parser.nextToken(lexer.TokenKindName) + if err != nil { return } + member.what, err = parser.parseType() + if err != nil { return } + } + + // see if value exists + if parser.token.Is(lexer.TokenKindNewline) { + parser.nextToken() + // if we have exited the member, return + if !parser.token.Is(lexer.TokenKindIndent) { return } + if parser.token.Value().(int) != 2 { return } + + err = parser.nextToken() + if err != nil { return } + } + + // if default value exists, get it + if !parser.token.Is(lexer.TokenKindBinaryAnd) { + member.argument, err = parser.parseArgument() + } + + // if there is a bit width specifier, 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 } + } + + err = 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 9863344..6619c1d 100644 --- a/parser/type_test.go +++ b/parser/type_test.go @@ -6,55 +6,34 @@ func TestType (test *testing.T) { checkTree ("../tests/parser/type", false, `:arf --- -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 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 + ro that 9384 + ro this 389 +type ro eInitAndDefine:aBasic + ro this 389 + ro that 9384 + ro born:Int 4 + ro in:Int + ro the:Int:3 (9348 92384 92834) + ro walls:String "live in the walls, die in the walls." type ro fBasic:Int -type ro gBasicInit:Int:<6> +type ro gBasicInit:Int + 6 type ro hIntArray:{Int ..} -type ro iIntArrayInit:Int:3: - < +type ro iIntArrayInit:Int:3 + ( 3298 923 92 - > + ) `, test) } diff --git a/tests/parser/data/main.arf b/tests/parser/data/main.arf index 824cacd..35bf1b5 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,33 +13,30 @@ data ro eIntegerArray16:Int:16 data ro fIntegerArrayVariable:{Int ..} -data ro gIntegerArrayInitialized:Int:16:< - 3948 293 293049 948 912 - 340 0 2304 0 4785 92 - > +data ro gIntegerArrayInitialized:Int:16 + (3948 293 293049 948 912 + 340 0 2304 0 4785 92) -data rw hIntegerPointerInit:{Int}:<[& integer]> +data rw hIntegerPointerInit:{Int} [& integer] -data rw iMutIntegerPointerInit:{Int}:mut:<[& integer]> +data rw iMutIntegerPointerInit:{Int}:mut + [& integer] -data ro jObject:Obj:( - .this:<324> - .that:<324>) +data ro jObject:Obj + (324 + 438) -data ro kNestedObject:Obj:( - .this:( - .bird0:<324> - .bird1:<"hello world">) - .ro newMember:Int:<9023> - .that:( - .bird2:<123.8439> - .bird3:<9328.21348239>)) +# TODO: at some point, have this syntax for object literals. terminate members +# with newlines. +# data ro jObject:Bird ( + # .this 324 + # .that 438) 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 9e2aedf..e935f73 100644 --- a/tests/parser/enum/main.arf +++ b/tests/parser/enum/main.arf @@ -11,26 +11,26 @@ enum ro Weekday:Int - 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>) +enum ro ThisIsTerrible:Vector + - up ( 0 -1) + - down ( 0 1) + - left (-1 0) + - right ( 1 0) diff --git a/tests/parser/face/main.arf b/tests/parser/face/main.arf index 4a78a7c..0a39686 100644 --- a/tests/parser/face/main.arf +++ b/tests/parser/face/main.arf @@ -1,7 +1,7 @@ :arf --- -face ro ReadWriter:Face +face ro aReadWriter:Face write > data:{Byte ..} < wrote:Int @@ -11,5 +11,10 @@ face ro ReadWriter:Face < read:Int < err:Error -face ro Destroyer:Face +face ro bDestroyer:Face destroy + +face ro cFuncInterface:Func + > something:Int + < someOutput:Int + < otherOutput:String diff --git a/tests/parser/func/main.arf b/tests/parser/func/main.arf index adee836..3c47e1c 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 @@ -122,14 +122,13 @@ func ro gControlFlow else otherThing -func ro hSetPhrase +func ro hDataInit --- - let x:Int:<3> + = x:Int 3 # loc is a reference, similar to * in C - 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>) + = y:{Int} [loc x] + = z:Int:8 (398 9 2309 983 -2387 + 478 555 123) + = bird:Bird ( + (99999) + 324) diff --git a/tests/parser/skim/main.arf b/tests/parser/skim/main.arf index 762a451..e2bfed6 100644 --- a/tests/parser/skim/main.arf +++ b/tests/parser/skim/main.arf @@ -6,37 +6,33 @@ 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 +data ro cNestedObject:Obj ( + (324 "hello world") + (123.8439 9328.21348239) +) data ro dUninitialized:Int:16:mut data ro eIntegerArrayInitialized:Int:16:mut - 3948 293 293049 948 912 - 340 0 2304 0 4785 92 + (3948 293 293049 948 912 + 340 0 2304 0 4785 92) func ro fComplexFunction --- = x:Int 3 - = y:{Int} [loc x] - = z:Int:8 + = y:{Int +} [loc x +] + = z:Int:8 ( 398 9 2309 983 -2387 - 478 555 123 - = bird:Bird - -- that - -- whenYou 99999 - -- this 324 + 478 555 123) + = bird:Bird ((99999) 324) func ro gExternalFunction > x:Int < arr:Int 5 - 34908 + (34908 39 3498 - 38 219 + 38 219) --- external diff --git a/tests/parser/type/main.arf b/tests/parser/type/main.arf index 8ffe9df..7236678 100644 --- a/tests/parser/type/main.arf +++ b/tests/parser/type/main.arf @@ -1,35 +1,36 @@ :arf --- -type ro aBasic:Obj:( - .ro that:Int - .ro this:Int) +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 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 cInit:Obj + ro that:String "hello world" + ro this:Int 23 -type ro dInitInherit:aBasic:( - .that:<9384> - .this:<389>) +# the semantic analyzer should let these sections restrict the permissions of +# inherited members, but it should not let the sections lessen the permissions. +type ro dInitInherit:aBasic + ro that 9384 + ro 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 eInitAndDefine:aBasic + ro this 389 + ro that 9384 + ro born:Int 4 + ro in:Int + ro the:Int:3 (9348 92384 92834) + ro walls:String "live in the walls, die in the walls." type ro fBasic:Int -type ro gBasicInit:Int:<6> +type ro gBasicInit:Int 6 type ro hIntArray:{Int ..} -type ro iIntArrayInit:Int:3: - <3298 923 92> +type ro iIntArrayInit:Int:3 + (3298 923 92)