Merge pull request 'type-section-rework' (#6) from type-section-rework into main

Reviewed-on: arf/arf#6
This commit is contained in:
Sasha Koshka 2022-09-17 16:36:27 +00:00
commit 844b1562c4
33 changed files with 1025 additions and 907 deletions

View File

@ -4,6 +4,6 @@ require "io"
func ro main
> arguments:{String ..}
< status:Int 0
< status:Int:<0>
---
io.println "hello world"

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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)
}

180
parser/default-values.go Normal file
View File

@ -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
// }

View File

@ -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
}

View File

@ -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)
}

View File

@ -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 }
}
}
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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,

View File

@ -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(&section)
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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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":

View File

@ -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")

View File

@ -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 <value>)
// (.name <value> .name (.name <value))
ArgumentKindObjectDefaultValues
// value value...
ArgumentKindArrayInitializationValues
// <4 32 98 5>
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

318
parser/type-notation.go Normal file
View File

@ -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:<value>
// 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:<value>
// 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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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:.,..()[]{}
+ - ++ -- * / @ ! % %= ~ ~= = == != < <= << <<= > >= >> >>= | |= || & &= && ^ ^=

View File

@ -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>

View File

@ -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>)

View File

@ -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>)

View File

@ -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

View File

@ -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

View File

@ -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>