Compare commits

...

61 Commits

Author SHA1 Message Date
06a99ce232 Implement new tokens
I think this is all of them. The test will tell.
2022-08-30 01:02:49 -04:00
Sasha Koshka
1c2194b68a Added text descriptions for new tokens 2022-08-25 23:21:00 -04:00
Sasha Koshka
453a596587 Added test case for new tokens 2022-08-25 23:17:42 -04:00
c3b6330b22 Added base function parsing 2022-08-25 20:01:12 -04:00
723b506005 Added test code for function sections 2022-08-25 16:08:18 -04:00
6bbee2e13b Created comprehensive test case 2022-08-25 15:46:35 -04:00
Sasha Koshka
9fd285920b Began writing test case for function sections 2022-08-25 13:31:09 -04:00
Sasha Koshka
e630ec6f04 Added function section to tree 2022-08-25 12:02:43 -04:00
Sasha Koshka
0ac71fa1c3 Added progress heatmap 2022-08-25 00:51:54 -04:00
Sasha Koshka
9232432c35 Implemented thos bad boys 2022-08-25 00:05:40 -04:00
Sasha Koshka
b536b01eeb Added new tokens to test case 2022-08-25 00:01:28 -04:00
Sasha Koshka
8175a9d4c5 Added some more tokens to the TokenKind enum 2022-08-24 23:58:21 -04:00
Sasha Koshka
3dd2ea83d3 I forgot the 2022-08-24 23:55:34 -04:00
Sasha Koshka
b7631530bc yeah 2022-08-24 23:54:06 -04:00
Sasha Koshka
fa1d8efe55 Its just as I feared. Identifier parsing doesn't work! 2022-08-24 23:50:16 -04:00
e74aff3299 Merge pull request 'tree-cleanup' (#9) from tree-cleanup into main
Reviewed-on: #9
2022-08-25 00:24:41 +00:00
Sasha Koshka
89a60e620e Altered objt section test case to not be alphabetically organized 2022-08-24 20:20:55 -04:00
Sasha Koshka
cd528552c8 Object sections now parse members into array 2022-08-24 20:19:14 -04:00
Sasha Koshka
067bf2f4df Altered tree so that object members are stored in an array 2022-08-24 20:09:57 -04:00
777c8df6a4 Changed the logo color because why not lol 2022-08-24 18:57:45 -04:00
c470997887 Did the same thing to interfaces 2022-08-24 18:57:07 -04:00
715766edb4 Objects can only inherit by specifiying an identifier 2022-08-24 18:52:31 -04:00
821fa0ecb3 Merge pull request 'objt-bitfields' (#8) from objt-bitfields into main
Reviewed-on: #8
2022-08-24 22:46:31 +00:00
e316eb7791 Changed bit field syntax to use an & symbol 2022-08-24 18:37:44 -04:00
731cc828ce Added untested bit width parsing 2022-08-24 18:29:15 -04:00
05aa0e6177 Added bitfields to object section test case 2022-08-24 18:23:11 -04:00
fb43f96acc Added bit fields to tree and ToString for object member 2022-08-24 18:22:47 -04:00
Sasha Koshka
b64fbd9fc4 Split tests into multiple files
This should make it easier to work on sections independantly of one another
without creating merge conflicts
2022-08-24 01:22:24 -04:00
Sasha Koshka
0d366964ca Enum members are now ordered 2022-08-24 01:16:44 -04:00
a5477717eb Merge pull request 'face-section' (#7) from face-section into main
Reviewed-on: #7
2022-08-24 04:57:14 +00:00
Sasha Koshka
0b80a55f79 Repaired output formatting of interface section 2022-08-24 00:53:42 -04:00
Sasha Koshka
08935d69c0 Parser actually adds interface behavior to interface 2022-08-24 00:52:37 -04:00
Sasha Koshka
39f8d7e4ac Fixed parsing of interface section behaviors 2022-08-24 00:25:52 -04:00
Sasha Koshka
1f88b54eaa Face sections are actually ToString'd now 2022-08-23 22:25:21 -04:00
b0d4ecc83f Added interface section parsing to body 2022-08-23 15:14:44 -04:00
4eac5c67aa Added untested interface section parsing 2022-08-23 15:13:00 -04:00
441b036a1c Updated test case to reflect previous commit 2022-08-23 14:07:56 -04:00
8817d72cb3 Interfaces can inherit other interfaces 2022-08-23 13:56:59 -04:00
3ef1e706b3 Added ToString method to face section 2022-08-23 13:54:44 -04:00
944fc8514e Add correct output for face test case 2022-08-23 13:46:20 -04:00
Sasha Koshka
cd55a0ad8d Add interface section to tree 2022-08-23 10:56:37 -04:00
Sasha Koshka
f95c7e0b1c Basic test file for interface section 2022-08-23 10:55:50 -04:00
15d1b602b3 Merge pull request 'enum-section' (#6) from enum-section into main
Reviewed-on: #6
2022-08-23 05:38:55 +00:00
Sasha Koshka
c29efd97ba Organized test case members alphabetically 2022-08-23 01:36:40 -04:00
Sasha Koshka
aa84d9a429 Removed space alignment and hex literals from test case check
ToString is not capable of producing this
2022-08-23 01:35:35 -04:00
Sasha Koshka
5dcf3b3d1a Fixed ToString formatting of enum 2022-08-23 01:33:28 -04:00
Sasha Koshka
d8074fa5cb Enum default values are now parsed properly
Previously the parser would stay on the member name and parse it the default
value. It now moves forward and catches the actual default value.
2022-08-23 01:30:56 -04:00
Sasha Koshka
6a6fe8353e Add untested enum parsing 2022-08-21 11:17:56 -04:00
Sasha Koshka
c4f763af5b Added test case for enum section 2022-08-21 02:48:36 -04:00
Sasha Koshka
6fbda34300 Add base enum parsing method 2022-08-21 02:42:25 -04:00
Sasha Koshka
59126f60cc Added enum sections to tree 2022-08-21 02:40:04 -04:00
Sasha Koshka
ca80a5968d Cleaned up example code and made it up-to-date 2022-08-20 15:54:10 -04:00
61819311e9 Merge pull request 'objt-section' (#5) from objt-section into main
Reviewed-on: #5
2022-08-20 19:47:44 +00:00
Sasha Koshka
f3b2d11f59 I swear its not my code thats wrong its the test
No like literally this keeps happening
2022-08-20 15:45:45 -04:00
Sasha Koshka
3900bbe7bf Parser test cases now print out line numbers 2022-08-20 15:45:01 -04:00
Sasha Koshka
b878017b81 The last item of object sections is now saved. 2022-08-20 15:22:25 -04:00
Sasha Koshka
5271876196 Changed data in object test to use objt keyword instead of type 2022-08-20 13:46:10 -04:00
Sasha Koshka
617d76fc46 Object sections now parse properly 2022-08-20 13:43:10 -04:00
Sasha Koshka
0ceaedbcd8 Object sections now ToString properly 2022-08-20 13:42:09 -04:00
Sasha Koshka
edb9c1a0b6 Fixed assignment to entry in nil map 2022-08-20 13:29:04 -04:00
Sasha Koshka
bd433fc65d Untested object section parsing 2022-08-20 13:26:24 -04:00
34 changed files with 1242 additions and 349 deletions

View File

@@ -16,7 +16,7 @@ A directory of ARF files is called a module, and modules will compile to object
files (one per module) using C as an intermediate language (maybe LLVM IR in the
future).
## Design aspects
## Design Aspects
These are some design goals that I have followed/am following:
@@ -32,7 +32,7 @@ These are some design goals that I have followed/am following:
- One line at a time - the language's syntax should encourage writing code that
flows vertically and not horizontally, with minimal nesting
## Planned features
## Planned Features
- Type definition through inheritence
- Struct member functions
@@ -49,3 +49,11 @@ These are some design goals that I have followed/am following:
- [ ] Semantic tree -> C -> object file
- [ ] Figure out HOW to implement generics
- [ ] Create a standard library
## Compiler Progress
<img src="assets/heatmap.png" alt="Progress heatmap" width="400">
- Yellow: needs to be completed for the MVP
- Lime: ongoing progress in this area
- Green: Already completed

BIN
assets/heatmap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View File

@@ -1,8 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 288 80" width="288" height="80">
<path d="M48 0L112 0L112 32L96 32L96 16L56 16L40 32L16 32L48 0Z" fill="#bf616a" fill-rule="evenodd" opacity="1" stroke="none"/>
<path d="M96 64L136 64L136 80L104 80L96 72L96 64Z" fill="#bf616a" fill-rule="evenodd" opacity="1" stroke="none"/>
<path d="M120 0L120 32L136 32L136 16L184 16L184 32L176 40L8 40L0 48L0 56L184 56L200 40L200 32L200 0L120 0Z" fill="#bf616a" fill-rule="evenodd" opacity="1" stroke="none"/>
<path d="M191 61L204 48L236 80L210 80L191 61Z" fill="#bf616a" fill-rule="evenodd" opacity="1" stroke="none"/>
<path d="M256 40L208 40L224 56L256 56L256 40Z" fill="#bf616a" fill-rule="evenodd" opacity="1" stroke="none"/>
<path d="M208 0L288 0L288 16L224 16L224 32L208 32L208 0Z" fill="#bf616a" fill-rule="evenodd" opacity="1" stroke="none"/>
<path d="M48 0L112 0L112 32L96 32L96 16L56 16L40 32L16 32L48 0Z" fill="#b81414" fill-rule="evenodd" opacity="1" stroke="none"/>
<path d="M96 64L136 64L136 80L104 80L96 72L96 64Z" fill="#b81414" fill-rule="evenodd" opacity="1" stroke="none"/>
<path d="M120 0L120 32L136 32L136 16L184 16L184 32L176 40L8 40L0 48L0 56L184 56L200 40L200 32L200 0L120 0Z" fill="#b81414" fill-rule="evenodd" opacity="1" stroke="none"/>
<path d="M191 61L204 48L236 80L210 80L191 61Z" fill="#b81414" fill-rule="evenodd" opacity="1" stroke="none"/>
<path d="M256 40L208 40L224 56L256 56L256 40Z" fill="#b81414" fill-rule="evenodd" opacity="1" stroke="none"/>
<path d="M208 0L288 0L288 16L224 16L224 32L208 32L208 0Z" fill="#b81414" fill-rule="evenodd" opacity="1" stroke="none"/>
</svg>

Before

Width:  |  Height:  |  Size: 847 B

After

Width:  |  Height:  |  Size: 847 B

View File

@@ -1,3 +1,9 @@
:arf
require "io"
---
func rr main
func ro main
> arguments:{String}
< status:Int 0
---
io.println "hello world"

View File

@@ -5,37 +5,31 @@ require "io"
---
# this is a global variable
data wn helloText:String "Hello, world!"
data pv helloText:String "Hello, world!"
# this is a struct definition
type rr Greeter:Obj
# "Hi." is a string constant. all Greeters will be initialized with a
# pointer to it. I don't know really it depends on what I decide that
# a String type even is.
wr text:String "Hi."
"sdfdsf" "ahh"
"asdf"
objt ro Greeter:Obj
rw text:String "Hi."
# this is a function
func rr main
> argc:Int
> argv:{String}
< status:Int 0
---
let greeter:Greeter:mut
greeter.setText helloText
greeter.greet
func ro main
> arguments:{String}
< status:Int 0
---
set greeter:Greeter:mut
greeter.setText helloText
greeter.greet
# this is a member function
func rr greet
@ greeter:{Greeter}
---
io.println greeter.text
func ro greet
@ greeter:{Greeter}
---
io.println greeter.text
# this is mutator member function
func rr setText
@ greeter:{Greeter}
> text:String
---
greeter.text.set text
func ro setText
@ greeter:{Greeter}
> text:String
---
greeter.text.set text

View File

@@ -1,11 +0,0 @@
:arf
require io
---
func rr main
> argc:Int
> argv:{String}
< status:Int
---
io.println [io.readln]
= status 0

View File

@@ -1,13 +0,0 @@
:arf
---
data:{Int 6}
-39480 398 29 0x3AFe3 0b10001010110 0o666
func rr literals
---
= stringLiteral:String "skadjlsakdj"
= intArrayLiteral:{Int 3} 2398
-2938 324
= runeLiteral:Rune 'a'
= floatArrayLiteral:{F64 5} 3248.23 0.324 -94.29

21
face_test.go Normal file
View File

@@ -0,0 +1,21 @@
package parser
import "testing"
func TestFace (test *testing.T) {
checkTree ("../tests/parser/face",
`:arf
---
face ro Destroyer:Face
destroy
face ro ReadWriter:Face
read
> into:{Byte ..}
< read:Int
< err:Error
write
> data:{Byte ..}
< wrote:Int
< err:Error
`, test)
}

View File

@@ -242,17 +242,40 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
err = lexer.nextRune()
case '!':
token := lexer.newToken()
token.kind = TokenKindExclamation
lexer.addToken(token)
err = lexer.nextRune()
if err != nil { return }
token.kind = TokenKindExclamation
if lexer.char == '=' {
token.kind = TokenKindNotEqualTo
err = lexer.nextRune()
token.location.SetWidth(2)
}
lexer.addToken(token)
case '%':
token := lexer.newToken()
token.kind = TokenKindPercent
lexer.addToken(token)
err = lexer.nextRune()
if err != nil { return }
token.kind = TokenKindPercent
if lexer.char == '=' {
token.kind = TokenKindPercentAssignment
err = lexer.nextRune()
token.location.SetWidth(2)
}
lexer.addToken(token)
case '~':
token := lexer.newToken()
err = lexer.nextRune()
if err != nil { return }
token.kind = TokenKindTilde
if lexer.char == '=' {
token.kind = TokenKindTildeAssignment
err = lexer.nextRune()
token.location.SetWidth(2)
}
lexer.addToken(token)
case '=':
token := lexer.newToken()
token.kind = TokenKindEqualTo
lexer.addToken(token)
err = lexer.nextRune()
case '<':
@@ -264,6 +287,15 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
token.kind = TokenKindLShift
err = lexer.nextRune()
token.location.SetWidth(2)
if lexer.char == '=' {
token.kind = TokenKindLShiftAssignment
err = lexer.nextRune()
token.location.SetWidth(2)
}
} else if lexer.char == '=' {
token.kind = TokenKindLessThanEqualTo
err = lexer.nextRune()
token.location.SetWidth(2)
}
lexer.addToken(token)
case '>':
@@ -275,6 +307,15 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
token.kind = TokenKindRShift
err = lexer.nextRune()
token.location.SetWidth(2)
if lexer.char == '=' {
token.kind = TokenKindRShiftAssignment
err = lexer.nextRune()
token.location.SetWidth(2)
}
} else if lexer.char == '=' {
token.kind = TokenKindGreaterThanEqualTo
err = lexer.nextRune()
token.location.SetWidth(2)
}
lexer.addToken(token)
case '|':
@@ -286,6 +327,10 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
token.kind = TokenKindLogicalOr
err = lexer.nextRune()
token.location.SetWidth(2)
} else if lexer.char == '=' {
token.kind = TokenKindBinaryOrAssignment
err = lexer.nextRune()
token.location.SetWidth(2)
}
lexer.addToken(token)
case '&':
@@ -297,6 +342,10 @@ func (lexer *LexingOperation) tokenizeSymbolBeginning () (err error) {
token.kind = TokenKindLogicalAnd
err = lexer.nextRune()
token.location.SetWidth(2)
} else if lexer.char == '=' {
token.kind = TokenKindBinaryAndAssignment
err = lexer.nextRune()
token.location.SetWidth(2)
}
lexer.addToken(token)
default:

View File

@@ -152,15 +152,27 @@ func TestTokenizeAll (test *testing.T) {
quickToken(1, TokenKindAt, nil),
quickToken(1, TokenKindExclamation, nil),
quickToken(1, TokenKindPercent, nil),
quickToken(2, TokenKindPercentAssignment, nil),
quickToken(1, TokenKindTilde, nil),
quickToken(2, TokenKindTildeAssignment, nil),
quickToken(1, TokenKindEqualTo, nil),
quickToken(2, TokenKindNotEqualTo, nil),
quickToken(1, TokenKindLessThan, nil),
quickToken(2, TokenKindLessThanEqualTo, nil),
quickToken(2, TokenKindLShift, nil),
quickToken(3, TokenKindLShiftAssignment, nil),
quickToken(1, TokenKindGreaterThan, nil),
quickToken(2, TokenKindGreaterThanEqualTo, nil),
quickToken(2, TokenKindRShift, nil),
quickToken(3, TokenKindRShiftAssignment, nil),
quickToken(1, TokenKindBinaryOr, nil),
quickToken(2, TokenKindBinaryOrAssignment, nil),
quickToken(2, TokenKindLogicalOr, nil),
quickToken(1, TokenKindBinaryAnd, nil),
quickToken(2, TokenKindBinaryAndAssignment, nil),
quickToken(2, TokenKindLogicalAnd, nil),
quickToken(1, TokenKindBinaryXor, nil),
quickToken(2, TokenKindBinaryXorAssignment, nil),
quickToken(1, TokenKindNewline, nil),
)
}

View File

@@ -43,16 +43,28 @@ const (
TokenKindAt
TokenKindExclamation
TokenKindPercent
TokenKindPercentAssignment
TokenKindTilde
TokenKindTildeAssignment
TokenKindEqualTo
TokenKindNotEqualTo
TokenKindLessThanEqualTo
TokenKindLessThan
TokenKindLShift
TokenKindLShiftAssignment
TokenKindGreaterThan
TokenKindGreaterThanEqualTo
TokenKindRShift
TokenKindRShiftAssignment
TokenKindBinaryOr
TokenKindBinaryOrAssignment
TokenKindLogicalOr
TokenKindBinaryAnd
TokenKindBinaryAndAssignment
TokenKindLogicalAnd
TokenKindBinaryXor
TokenKindBinaryXorAssignment
)
// Token represents a single token. It holds its location in the file, as well
@@ -171,24 +183,48 @@ func (tokenKind TokenKind) Describe () (description string) {
description = "Exclamation"
case TokenKindPercent:
description = "Percent"
case TokenKindPercentAssignment:
description = "PercentAssignment"
case TokenKindTilde:
description = "Tilde"
case TokenKindTildeAssignment:
description = "TildeAssignment"
case TokenKindEqualTo:
description = "EqualTo"
case TokenKindNotEqualTo:
description = "NotEqualTo"
case TokenKindLessThan:
description = "LessThan"
case TokenKindLessThanEqualTo:
description = "LessThanEqualTo"
case TokenKindLShift:
description = "LShift"
case TokenKindLShiftAssignment:
description = "LShiftAssignment"
case TokenKindGreaterThan:
description = "GreaterThan"
case TokenKindGreaterThanEqualTo:
description = "GreaterThanEqualTo"
case TokenKindRShift:
description = "RShift"
case TokenKindRShiftAssignment:
description = "RShiftAssignment"
case TokenKindBinaryOr:
description = "BinaryOr"
case TokenKindBinaryOrAssignment:
description = "BinaryOrAssignment"
case TokenKindLogicalOr:
description = "LogicalOr"
case TokenKindBinaryAnd:
description = "BinaryAnd"
case TokenKindBinaryAndAssignment:
description = "BinaryAndAssignment"
case TokenKindLogicalAnd:
description = "LogicalAnd"
case TokenKindBinaryXor:
description = "BinaryXor"
case TokenKindBinaryXorAssignment:
description = "BinaryXorAssignment"
}
return

View File

@@ -32,15 +32,39 @@ func (parser *ParsingOperation) parseBody () (err error) {
case "objt":
var section *ObjtSection
section, err = parser.parseObjtSection()
if parser.tree.typeSections == nil {
parser.tree.typeSections =
make(map[string] *TypeSection)
if parser.tree.objtSections == nil {
parser.tree.objtSections =
make(map[string] *ObjtSection)
}
parser.tree.objtSections[section.name] = section
if err != nil { return }
case "face":
var section *FaceSection
section, err = parser.parseFaceSection()
if parser.tree.faceSections == nil {
parser.tree.faceSections =
make(map[string] *FaceSection)
}
parser.tree.faceSections[section.name] = section
if err != nil { return }
case "enum":
var section *EnumSection
section, err = parser.parseEnumSection()
if parser.tree.enumSections == nil {
parser.tree.enumSections =
make(map[string] *EnumSection)
}
parser.tree.enumSections[section.name] = section
if err != nil { return }
case "func":
var section *FuncSection
section, err = parser.parseFuncSection()
if parser.tree.funcSections == nil {
parser.tree.funcSections =
make(map[string] *FuncSection)
}
parser.tree.funcSections[section.name] = section
if err != nil { return }
default:
err = parser.token.NewError (
"unknown section type \"" + sectionType + "\"",

View File

@@ -289,8 +289,6 @@ func (parser *ParsingOperation) parseIdentifier () (
identifier.location = parser.token.Location()
for {
// TODO: eat up newlines and tabs after the dot, but not before
// it.
if !parser.token.Is(lexer.TokenKindName) { break }
identifier.trail = append (
@@ -301,6 +299,18 @@ func (parser *ParsingOperation) parseIdentifier () (
if err != nil { return }
if !parser.token.Is(lexer.TokenKindDot) { break }
err = parser.nextToken()
if err != nil { return }
// allow the identifier to continue on to the next line if there
// is a line break right after the dot
for parser.token.Is(lexer.TokenKindNewline) ||
parser.token.Is(lexer.TokenKindIndent) {
err = parser.nextToken()
if err != nil { return }
}
}
return

38
parser/data_test.go Normal file
View File

@@ -0,0 +1,38 @@
package parser
import "testing"
func TestData (test *testing.T) {
checkTree ("../tests/parser/data",
`:arf
---
data ro integer:Int 3202
data ro integerArray16:{Int 16}
data ro integerArrayInitialized:{Int 16}
3948
293
293049
948
912
340
0
2304
0
4785
92
data ro integerArrayVariable:{Int ..}
data ro integerPointer:{Int}
data ro mutInteger:Int:mut 3202
data ro mutIntegerPointer:{Int}:mut
data ro nestedObject:Obj
.that
.bird2 123.8439
.bird3 9328.21348239
.this
.bird0 324
.bird1 "hello world"
data ro object:thing.thing.thing.thing
.that 2139
.this 324
`, test)
}

93
parser/enum.go Normal file
View File

@@ -0,0 +1,93 @@
package parser
import "git.tebibyte.media/sashakoshka/arf/types"
import "git.tebibyte.media/sashakoshka/arf/lexer"
import "git.tebibyte.media/sashakoshka/arf/infoerr"
func (parser *ParsingOperation) parseEnumSection () (
section *EnumSection,
err error,
) {
err = parser.expect(lexer.TokenKindName)
if err != nil { return }
section = &EnumSection { 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.what, err = parser.parseType()
if err != nil { return }
err = parser.expect(lexer.TokenKindNewline)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
// parse members
err = parser.parseEnumMembers(section)
if err != nil { return }
if len(section.members) == 0 {
infoerr.NewError (
section.location,
"defining an enum with no members",
infoerr.ErrorKindWarn).Print()
}
return
}
// parseEnumMembers parses a list of members for an enum section. Indentation
// level is assumed.
func (parser *ParsingOperation) parseEnumMembers (
into *EnumSection,
) (
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 }
member := EnumMember { }
// get name
err = parser.nextToken(lexer.TokenKindName)
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 }
err = parser.expect(lexer.TokenKindNewline)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
}
}
}

38
parser/enum_test.go Normal file
View File

@@ -0,0 +1,38 @@
package parser
import "testing"
func TestEnum (test *testing.T) {
checkTree ("../tests/parser/enum",
`:arf
---
enum ro AffrontToGod:{Int 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 Weekday:Int
sunday
monday
tuesday
wednesday
thursday
friday
saturday
`, test)
}

132
parser/face.go Normal file
View File

@@ -0,0 +1,132 @@
package parser
import "git.tebibyte.media/sashakoshka/arf/types"
import "git.tebibyte.media/sashakoshka/arf/lexer"
import "git.tebibyte.media/sashakoshka/arf/infoerr"
// parseFaceSection parses an interface section.
func (parser *ParsingOperation) parseFaceSection () (
section *FaceSection,
err error,
) {
err = parser.expect(lexer.TokenKindName)
if err != nil { return }
section = &FaceSection {
location: parser.token.Location(),
behaviors: make(map[string] FaceBehavior),
}
// 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 interface
err = parser.nextToken(lexer.TokenKindColon)
if err != nil { return }
err = parser.nextToken(lexer.TokenKindName)
if err != nil { return }
section.inherits, err = parser.parseIdentifier()
if err != nil { return }
err = parser.nextToken(lexer.TokenKindNewline)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
// parse members
for {
// if we've left the block, stop parsing
if !parser.token.Is(lexer.TokenKindIndent) { return }
if parser.token.Value().(int) != 1 { return }
// parse behavior
behaviorBeginning := parser.token.Location()
var behavior FaceBehavior
behavior, err = parser.parseFaceBehavior()
// add to section
_, exists := section.behaviors[behavior.name]
if exists {
err = infoerr.NewError (
behaviorBeginning,
"multiple behaviors named " + behavior.name +
" in this interface",
infoerr.ErrorKindError)
return
}
section.behaviors[behavior.name] = behavior
if err != nil { return }
}
return
}
// parseFaceBehavior parses a single interface behavior. Indentation level is
// assumed.
func (parser *ParsingOperation) parseFaceBehavior () (
behavior FaceBehavior,
err error,
) {
err = parser.expect(lexer.TokenKindIndent)
if err != nil { return }
// get name
err = parser.nextToken(lexer.TokenKindName)
if err != nil { return }
behavior.name = parser.token.Value().(string)
err = parser.nextToken(lexer.TokenKindNewline)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
for {
// if we've left the block, stop parsing
if !parser.token.Is(lexer.TokenKindIndent) { return }
if parser.token.Value().(int) != 2 { return }
// get preceding symbol
err = parser.nextToken (
lexer.TokenKindGreaterThan,
lexer.TokenKindLessThan)
if err != nil { return }
kind := parser.token.Kind()
var declaration Declaration
// get name
err = parser.nextToken(lexer.TokenKindName)
if err != nil { return }
declaration.name = parser.token.Value().(string)
// parse inherited type
err = parser.nextToken(lexer.TokenKindColon)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
declaration.what, err = parser.parseType()
if err != nil { return }
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)
}
}
return
}

30
parser/func.go Normal file
View File

@@ -0,0 +1,30 @@
package parser
import "git.tebibyte.media/sashakoshka/arf/types"
import "git.tebibyte.media/sashakoshka/arf/lexer"
// import "git.tebibyte.media/sashakoshka/arf/infoerr"
// parseFunc parses a function section.
func (parser *ParsingOperation) parseFuncSection () (
section *FuncSection,
err error,
) {
err = parser.expect(lexer.TokenKindName)
if err != nil { return }
section = &FuncSection { location: parser.token.Location() }
err = parser.nextToken(lexer.TokenKindPermission)
if err != nil { return }
section.permission = parser.token.Value().(types.Permission)
err = parser.nextToken(lexer.TokenKindName)
if err != nil { return }
section.name = parser.token.Value().(string)
err = parser.nextToken(lexer.TokenKindNewline)
if err != nil { return }
return
}

111
parser/func_test.go Normal file
View File

@@ -0,0 +1,111 @@
package parser
import "testing"
func TestFunc (test *testing.T) {
checkTree ("../tests/parser/func",
`:arf
---
func ro aBasicExternal
> someInput:Int:mut
< someOutput:Int 4
---
external
func ro bMethod
@ bird:{Bird}
> someInput:Int:mut
< someOutput:Int 4
---
external
func ro cBasicPhrases
---
[fn 329 983 09]
[fn 329 983 09]
[fn 329 983 091]
[fn [gn 329 983 091] 123]
func ro dArgumentTypes
---
[bird tree butterfly.wing "hello world" grass:{Int:mut 8}]
func ro eMath
[> x:Int]
[> y:Int]
[< z:Int]
[---]
[++ x]
[-- y]
[set z [+ [* 0392 00] 98 x [/ 9832 y] 930]]
[! true]
[~ 0b01]
[% 873 32]
[= 5 5]
[!= 4 4]
[<= 4 98]
[< 4 98]
[<< 0x0F 4]
[>= 98 4]
[> 98 4]
[>> 0xF0 4]
[| 0b01 0b10]
[& 0b110 0b011]
[&& true true]
[|| true false]
func ro fReturnDirection
< err:Error
---
[someFunc 498 2980 90] -> thing:Int err
[otherFunc] -> thing err:Error
[fn 329 983 091] -> thing:Int err
func ro gControlFlow
---
[if condition]
[something]
[if condition]
[something]
[elseif]
[otherThing]
[else]
[finalThing]
[while [< x 432]]
[something]
[switch value]
[: 324]
[something]
[: 93284]
otherThing
[: 9128 34738 7328]
multipleCases
[:]
[defaultThing]
[for index:Size element:Int someArray]
[something]
[someNextThing]
[justMakingSureBlockParsingWorks]
[if condition]
[if condition]
[nestedThing]
[else]
[otherThing]
[else]
[if condition]
[nestedThing]
[else]
[otherThing]
func hSetPhrase
---
[set x:Int 3]
[set y:{Int} [. x]]
[set z:{Int 8}]
398
9
2309
983
-2387
478
555
123
[set bird:Bird]
.that
.whenYou 99999
.this 324
`, test)
}

14
parser/meta_test.go Normal file
View File

@@ -0,0 +1,14 @@
package parser
import "testing"
func TestMeta (test *testing.T) {
checkTree ("../tests/parser/meta",
`:arf
author "Sasha Koshka"
license "GPLv3"
require "someModule"
require "otherModule"
---
`, test)
}

127
parser/objt.go Normal file
View File

@@ -0,0 +1,127 @@
package parser
import "git.tebibyte.media/sashakoshka/arf/types"
import "git.tebibyte.media/sashakoshka/arf/lexer"
import "git.tebibyte.media/sashakoshka/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 = &ObjtSection { 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 }
println(parser.token.Describe())
// 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.defaultValue,
err = parser.parseInitializationValues(1)
if err != nil { return }
} else {
member.defaultValue, err = parser.parseArgument()
if err != nil { return }
err = parser.expect(lexer.TokenKindNewline)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
}
return
}

31
parser/objt_test.go Normal file
View File

@@ -0,0 +1,31 @@
package parser
import "testing"
func TestObjt (test *testing.T) {
checkTree ("../tests/parser/objt",
`: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

@@ -1,150 +0,0 @@
package parser
import "io"
import "testing"
// import "git.tebibyte.media/sashakoshka/arf/types"
func checkTree (modulePath string, correct string, test *testing.T) {
tree, err := Parse(modulePath)
treeString := tree.ToString(0)
treeRunes := []rune(treeString)
test.Log("CORRECT TREE:")
test.Log(correct)
test.Log("WHAT WAS PARSED:")
test.Log(treeString)
if err != io.EOF && err != nil {
test.Log("returned error:")
test.Log(err.Error())
test.Fail()
return
}
equal := true
line := 0
column := 0
for index, correctChar := range correct {
if index >= len(treeRunes) {
test.Log (
"parsed is too short at line", line + 1,
"col", column + 1)
test.Fail()
return
}
if correctChar != treeRunes[index] {
test.Log (
"trees not equal at line", line + 1,
"col", column + 1)
test.Log("correct: [" + string(correctChar) + "]")
test.Log("got: [" + string(treeRunes[index]) + "]")
test.Fail()
return
}
if correctChar == '\n' {
line ++
column = 0
} else {
column ++
}
}
if len(treeString) > len(correct) {
test.Log("parsed is too long")
test.Fail()
return
}
if !equal {
return
}
}
func TestMeta (test *testing.T) {
checkTree ("../tests/parser/meta",
`:arf
author "Sasha Koshka"
license "GPLv3"
require "someModule"
require "otherModule"
---
`, test)
}
func TestData (test *testing.T) {
checkTree ("../tests/parser/data",
`:arf
---
data ro integer:Int 3202
data ro integerArray16:{Int 16}
data ro integerArrayInitialized:{Int 16}
3948
293
293049
948
912
340
0
2304
0
4785
92
data ro integerArrayVariable:{Int ..}
data ro integerPointer:{Int}
data ro mutInteger:Int:mut 3202
data ro mutIntegerPointer:{Int}:mut
data ro nestedObject:Obj
.that
.bird2 123.8439
.bird3 9328.21348239
.this
.bird0 324
.bird1 "hello world"
data ro object:Obj
.that 2139
.this 324
`, test)
}
func TestType (test *testing.T) {
checkTree ("../tests/parser/type",
`:arf
---
type ro Basic:Int
type ro BasicInit:Int 6
type ro IntArray:{Int ..}
type ro IntArrayInit:{Int 3}
3298
923
92
`, test)
}
func TestObjt (test *testing.T) {
checkTree ("../tests/parser/objt",
`:arf
---
type ro Basic:Obj
ro that:Basic
ro this:Basic
type ro ComplexInit:Obj
ro basic:Int 87
ro complex0:Bird
.that 98
.this 2
ro complex1:Bird
.that 98902
.this 235
ro whatever:{Int 3}
230984
849
394580
type ro Init:Obj
ro that:String "hello world"
ro this:Int
`, test)
}

74
parser/test-common.go Normal file
View File

@@ -0,0 +1,74 @@
package parser
import "io"
import "strings"
import "testing"
// import "git.tebibyte.media/sashakoshka/arf/types"
func checkTree (modulePath string, correct string, test *testing.T) {
tree, err := Parse(modulePath)
treeString := tree.ToString(0)
treeRunes := []rune(treeString)
test.Log("CORRECT TREE:")
logWithLineNumbers(correct, test)
test.Log("WHAT WAS PARSED:")
logWithLineNumbers(treeString, test)
if err != io.EOF && err != nil {
test.Log("returned error:")
test.Log(err.Error())
test.Fail()
return
}
equal := true
line := 0
column := 0
for index, correctChar := range correct {
if index >= len(treeRunes) {
test.Log (
"parsed is too short at line", line + 1,
"col", column + 1)
test.Fail()
return
}
if correctChar != treeRunes[index] {
test.Log (
"trees not equal at line", line + 1,
"col", column + 1)
test.Log("correct: [" + string(correctChar) + "]")
test.Log("got: [" + string(treeRunes[index]) + "]")
test.Fail()
return
}
if correctChar == '\n' {
line ++
column = 0
} else {
column ++
}
}
if len(treeString) > len(correct) {
test.Log("parsed is too long")
test.Fail()
return
}
if !equal {
return
}
}
func logWithLineNumbers (bigString string, test *testing.T) {
lines := strings.Split (
strings.Replace(bigString, "\t", " ", -1), "\n")
for index, line := range lines {
test.Logf("%3d | %s", index + 1, line)
}
}

View File

@@ -51,6 +51,21 @@ func (tree *SyntaxTree) ToString (indent int) (output string) {
output += tree.typeSections[name].ToString(indent)
}
objtSectionKeys := sortMapKeysAlphabetically(tree.objtSections)
for _, name := range objtSectionKeys {
output += tree.objtSections[name].ToString(indent)
}
enumSectionKeys := sortMapKeysAlphabetically(tree.enumSections)
for _, name := range enumSectionKeys {
output += tree.enumSections[name].ToString(indent)
}
faceSectionKeys := sortMapKeysAlphabetically(tree.faceSections)
for _, name := range faceSectionKeys {
output += tree.faceSections[name].ToString(indent)
}
dataSectionKeys := sortMapKeysAlphabetically(tree.dataSections)
for _, name := range dataSectionKeys {
output += tree.dataSections[name].ToString(indent)
@@ -276,13 +291,17 @@ func (section *TypeSection) ToString (indent int) (output string) {
return
}
func (member *ObjtMember) ToString (indent int) (output string) {
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.defaultValue.kind == ArgumentKindObjectInitializationValues ||
member.defaultValue.kind == ArgumentKindArrayInitializationValues
@@ -314,3 +333,59 @@ func (section *ObjtSection) ToString (indent int) (output string) {
return
}
func (section *EnumSection) ToString (indent int) (output string) {
output += doIndent (
indent,
"enum ",
section.permission.ToString(), " ",
section.name, ":",
section.what.ToString(), "\n")
for _, member := range section.members {
output += doIndent(indent + 1, member.name)
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 + 2, true)
} else {
output += " " + member.value.ToString(0, false)
output += "\n"
}
}
return
}
func (section *FaceSection) ToString (indent int) (output string) {
output += doIndent (
indent,
"face ",
section.permission.ToString(), " ",
section.name, ":",
section.inherits.ToString(), "\n")
for _, name := range sortMapKeysAlphabetically(section.behaviors) {
behavior := section.behaviors[name]
output += behavior.ToString(indent + 1)
}
return
}
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")
}
for _, outputItem := range behavior.outputs {
output += doIndent(indent + 1, "< ", outputItem.ToString(), "\n")
}
return
}

View File

@@ -13,7 +13,10 @@ type SyntaxTree struct {
requires []string
typeSections map[string] *TypeSection
objtSections map[string] *ObjtSection
enumSections map[string] *EnumSection
faceSections map[string] *FaceSection
dataSections map[string] *DataSection
funcSections map[string] *FuncSection
}
// Identifier represents a chain of arguments separated by a dot.
@@ -178,6 +181,7 @@ type ObjtMember struct {
name string
what Type
bitWidth uint64
permission types.Permission
defaultValue Argument
}
@@ -187,7 +191,59 @@ type ObjtSection struct {
location file.Location
name string
inherits Type
inherits Identifier
permission types.Permission
members map[string] ObjtMember
members []ObjtMember
}
type EnumMember struct {
location file.Location
name string
value Argument
}
// EnumSection represents an enumerated type section.
type EnumSection struct {
location file.Location
name string
what Type
permission types.Permission
members []EnumMember
}
// FaceBehavior represents a behavior of an interface section.
type FaceBehavior struct {
location file.Location
name string
inputs []Declaration
outputs []Declaration
}
// FaceSection represents an interface type section.
type FaceSection struct {
location file.Location
name string
inherits Identifier
permission types.Permission
behaviors map[string] FaceBehavior
}
// Block represents a scoped/indented block of code.
// TODO: blocks will not directly nest. nested blocks will be stored as a part
// of certain control flow statements.
type Block []Phrase
// FuncSection represents a function section.
type FuncSection struct {
location file.Location
name string
permission types.Permission
receiver *Declaration
inputs []Declaration
outputs []Declaration
root *Block
}

View File

@@ -2,9 +2,10 @@ package parser
import "git.tebibyte.media/sashakoshka/arf/types"
import "git.tebibyte.media/sashakoshka/arf/lexer"
import "git.tebibyte.media/sashakoshka/arf/infoerr"
// import "git.tebibyte.media/sashakoshka/arf/infoerr"
// parseTypeSection parses a type definition.
// parseTypeSection parses a blind type definition, meaning it can inherit from
// anything including primitives, but cannot define structure.
func (parser *ParsingOperation) parseTypeSection () (
section *TypeSection,
err error,
@@ -14,50 +15,33 @@ func (parser *ParsingOperation) parseTypeSection () (
section = &TypeSection { location: parser.token.Location() }
// parse root node
err = parser.nextToken()
if err != nil { return }
section.root, err = parser.parseTypeNode(0)
return
}
// parseTypeNode parses a single type definition node recursively.
func (parser *ParsingOperation) parseTypeNode (
baseIndent int,
) (
node TypeNode,
err error,
) {
node.children = make(map[string] TypeNode)
// get permission
err = parser.expect(lexer.TokenKindPermission)
err = parser.nextToken(lexer.TokenKindPermission)
if err != nil { return }
node.permission = parser.token.Value().(types.Permission)
section.permission = parser.token.Value().(types.Permission)
// get name
err = parser.nextToken(lexer.TokenKindName)
if err != nil { return }
node.name = parser.token.Value().(string)
section.name = parser.token.Value().(string)
// get inherited type
// parse inherited type
err = parser.nextToken(lexer.TokenKindColon)
if err != nil { return }
err = parser.nextToken()
if err != nil { return }
node.what, err = parser.parseType()
section.inherits, err = parser.parseType()
if err != nil { return }
// get value, or child nodes
// parse default values
if parser.token.Is(lexer.TokenKindNewline) {
err = parser.nextToken()
if err != nil { return }
err = parser.parseTypeNodeBlock(baseIndent, &node)
section.defaultValue, err = parser.parseInitializationValues(0)
if err != nil { return }
} else {
node.defaultValue, err = parser.parseArgument()
section.defaultValue, err = parser.parseArgument()
if err != nil { return }
err = parser.expect(lexer.TokenKindNewline)
@@ -67,101 +51,3 @@ func (parser *ParsingOperation) parseTypeNode (
}
return
}
// parseTypeNodeBlock starts on the line after a type node, and parses what
// could be either an array initialization, an object initialization, or more
// child nodes. It is similar to parseInitializationValues. If none of these
// things were found the parser stays at the beginning of the line and the
// method returns.
func (parser *ParsingOperation) parseTypeNodeBlock (
baseIndent int,
parent *TypeNode,
) (
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 }
thingLocation := parser.token.Location()
err = parser.nextToken()
if err != nil { return }
if parser.token.Is(lexer.TokenKindDot) {
// object initialization
parser.previousToken()
initializationArgument := Argument { location: thingLocation }
var initializationValues ObjectInitializationValues
initializationValues, err = parser.parseObjectInitializationValues()
initializationArgument.kind = ArgumentKindObjectInitializationValues
initializationArgument.value = &initializationValues
parent.defaultValue = initializationArgument
} else if parser.token.Is(lexer.TokenKindPermission) {
// child members
parser.previousToken()
err = parser.parseTypeNodeChildren(parent)
} else {
// array initialization
parser.previousToken()
initializationArgument := Argument { location: thingLocation }
var initializationValues ArrayInitializationValues
initializationValues, err = parser.parseArrayInitializationValues()
initializationArgument.kind = ArgumentKindArrayInitializationValues
initializationArgument.value = &initializationValues
parent.defaultValue = initializationArgument
}
return
}
// parseTypeNodeChildren parses child type nodes into a parent type node.
func (parser *ParsingOperation) parseTypeNodeChildren (
parent *TypeNode,
) (
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 {
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 type node
err = parser.nextToken()
if err != nil { return }
var child TypeNode
child, err = parser.parseTypeNode(baseIndent)
// if the member has already been listed, throw an error
_, exists := parent.children[child.name]
if exists {
err = parser.token.NewError (
"duplicate member \"" + child.name +
"\" in object member initialization",
infoerr.ErrorKindError)
return
}
// store in parent
parent.children[child.name] = child
}
return
}

17
parser/type_test.go Normal file
View File

@@ -0,0 +1,17 @@
package parser
import "testing"
func TestType (test *testing.T) {
checkTree ("../tests/parser/type",
`:arf
---
type ro Basic:Int
type ro BasicInit:Int 6
type ro IntArray:{Int ..}
type ro IntArrayInit:{Int 3}
3298
923
92
`, test)
}

View File

@@ -1,3 +1,3 @@
:arf
--- rw -> -349820394 932748397 239485.37520 "hello world!\n" 'E' helloWorld:.,..[]{}
+ - ++ -- * / @ ! % ~ < << > >> | || & &&
+ - ++ -- * / @ ! % %= ~ ~= = != < <= << <<= > >= >> >>= | |= || & &= && ^ ^=

View File

@@ -22,7 +22,9 @@ data ro integerArrayInitialized:{Int 16}
# data wr mutIntegerPointerInit:{Int}:mut [& integer]
data ro object:Obj
# TODO: maybe test identifiers somewhere else?
data ro object:thing.thing.
thing.thing
.this 324
.that 2139

View File

@@ -0,0 +1,30 @@
:arf
---
enum ro Weekday:Int
sunday
monday
tuesday
wednesday
thursday
friday
saturday
enum ro NamedColor:U32
red 0xFF0000
green 0x00FF00
blue 0x0000FF
enum ro AffrontToGod:{Int 4}
bird0
28394 9328
398 9
bird1
23 932832
398
2349
bird2
1
2
3
4

View File

@@ -0,0 +1,15 @@
:arf
---
face ro ReadWriter:Face
write
> data:{Byte ..}
< wrote:Int
< err:Error
read
> into:{Byte ..}
< read:Int
< err:Error
face ro Destroyer:Face
destroy

134
tests/parser/func/main.arf Normal file
View File

@@ -0,0 +1,134 @@
:arf
---
func ro aBasicExternal
> someInput:Int:mut
< someOutput:Int 4
---
external
func ro bMethod
@ bird:{Bird}
> someInput:Int:mut
< someOutput:Int 4
---
external
func ro cBasicPhrases
---
fn 329 983 09
[fn 329 983 09]
[fn
329
983
091]
fn [gn
329 983
091] 123
func ro dArgumentTypes
---
[bird tree butterfly.wing "hello world"
grass:{Int:mut 8}]
func ro eMath
> x:Int
> y:Int
< z:Int
---
++ x
-- y
set z [+ [* 0392 00] 98 x [/ 9832 y] 930]
# TODO: need tokens ~=
! true
~ 0b01
# ~= x
% 873 32
= 5 5
!= 4 4
<= 4 98
< 4 98
<< 0x0F 4
# <<= x 4
>= 98 4
> 98 4
>> 0xF0 4
# >>= x 4
| 0b01 0b10
# |= x 0b10
& 0b110 0b011
# &= x 0b011
&& true true
|| true false
func ro fReturnDirection
< err:Error
---
someFunc 498 2980 90 -> thing:Int err
otherFunc -> thing err:Error
[fn
329
983
091] -> thing:Int err
func ro gControlFlow
---
if condition
something
if condition
something
elseif
[otherThing]
else
finalThing
while [< x 432]
something
switch value
: 324
something
[: 93284]
otherThing
: 9128 34738 7328
multipleCases
:
[defaultThing]
for index:Size element:Int someArray
something
someNextThing
justMakingSureBlockParsingWorks
[if condition]
if condition
nestedThing
else
otherThing
else
if condition
nestedThing
else
otherThing
func hSetPhrase
---
set x:Int 3
# TODO: this should be the "location of" phrase. update other things to
# match.
set y:{Int} [. x]
set z:{Int 8}
398 9 2309 983 -2387
478 555 123
set bird:Bird
.that
.whenYou 99999
.this 324

View File

@@ -4,6 +4,10 @@ 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