diff options
-rwxr-xr-x | gobuild.sh | 1 | ||||
-rw-r--r-- | out.tnp | 1 | ||||
-rw-r--r-- | qualifiers.txt | 71 | ||||
-rw-r--r-- | small-tests/base.tnsl (renamed from base.tnsl) | 0 | ||||
-rw-r--r-- | small-tests/examp.tnsl (renamed from examp.tnsl) | 0 | ||||
-rw-r--r-- | small-tests/out.tnt | 1 | ||||
-rw-r--r-- | small-tests/test.tnsl | 13 | ||||
-rw-r--r-- | spec/compiler/compiler.txt | 9 | ||||
-rw-r--r-- | spec/compiler/pre-processor.txt | 6 | ||||
-rw-r--r-- | spec/iex/iex-spec.txt | 128 | ||||
-rw-r--r-- | spec/libts.txt | 93 | ||||
-rw-r--r-- | spec/spec.txt | 99 | ||||
-rw-r--r-- | src/main.go | 2 | ||||
-rw-r--r-- | src/tparse/resolver.go | 24 | ||||
-rw-r--r-- | src/tparse/tree-list.go | 45 | ||||
-rw-r--r-- | src/tparse/tree-statement.go | 55 | ||||
-rw-r--r-- | src/tparse/tree-value.go | 130 | ||||
-rw-r--r-- | src/tparse/tree.go | 15 | ||||
-rw-r--r-- | src/tparse/type.go | 5 | ||||
-rw-r--r-- | tests/block-test.tnsl | 13 | ||||
-rw-r--r-- | tests/parameter-test.tnsl | 2 | ||||
-rwxr-xr-x | tests/run-tests.sh | 18 | ||||
-rw-r--r-- | tests/statement-test.tnsl | 6 |
23 files changed, 603 insertions, 134 deletions
@@ -4,4 +4,5 @@ SRCDIR=$(pwd) export GOPATH="$GOPATH:$SRCDIR" +go env -w GO111MODULE=off go build -o build/parse src/main.go diff --git a/out.tnp b/out.tnp deleted file mode 100644 index bc7c455..0000000 --- a/out.tnp +++ /dev/null @@ -1 +0,0 @@ -[{0 : 12 0} {6 import 12 1} {4 'what/what.tnsl' 12 8} {8 a 12 25} {0 : 14 0} {6 import 14 1} {4 "what/what.tnsl" 14 8} {0 ; 19 0} {5 int 19 1} {8 s 19 5} {3 = 19 7} {4 3 19 9} {0 ; 21 0} {5 byte 21 1} {8 bitbyte 21 6} {3 = 21 14} {3 . 21 16} {4 2 21 17} {2 /; 28 0} {0 ; 30 2} {5 int 30 3} {8 d 30 7} {3 = 30 9} {4 1 30 11} {0 ; 32 2} {8 s 32 3} {3 = 32 5} {8 d 32 7} {2 ;/ 34 0} {2 /; 43 0} {8 main 43 2} {2 ( 43 7} {2 { 43 8} {2 } 43 9} {8 string 43 10} {8 str 43 17} {2 ) 43 20} {2 [ 43 22} {5 int 43 23} {2 ] 43 26} {0 ; 51 2} {5 int 51 3} {8 i 51 7} {3 = 51 9} {4 1 51 11} {0 ; 52 2} {3 ~ 52 3} {5 int 52 4} {8 j 52 8} {3 ~= 52 10} {8 i 52 13} {8 j 53 2} {3 ~ 53 3} {3 = 53 5} {4 2 53 7} {2 /; 58 2} {7 loop 58 4} {2 [ 58 9} {8 i 58 10} {3 !== 58 11} {4 1 58 14} {2 ] 58 16} {0 ; 60 4} {8 i 60 6} {3 = 60 8} {4 1 60 10} {2 ;/ 61 2} {2 ;/ 63 0} {0 ; 68 0} {7 struct 68 1} {2 [ 68 8} {8 s1 68 9} {2 ] 68 11} {2 { 68 13} {8 string 68 14} {8 Name 68 21} {1 , 68 25} {8 string 68 27} {8 Message 68 34} {3 = 68 42} {4 "Default message (c-style strings)" 68 44} {2 } 68 79} {0 ; 71 0} {7 struct 71 1} {2 [ 71 8} {8 s1 71 9} {2 ] 71 11} {2 { 71 13} {8 string 72 4} {8 Name 72 11} {1 , 72 15} {8 string 73 4} {8 Message 73 11} {3 = 73 19} {4 "Default message (c-style strings)" 73 21} {2 } 74 0} {0 ; 77 0} {8 s1 77 1} {8 a 77 4} {3 = 77 6} {2 { 77 8} {2 } 77 9} {0 ; 79 0} {8 s1 79 1} {8 a 79 4} {2 { 79 5} {2 } 79 6} {0 ; 80 0} {8 a 80 1} {3 . 80 2} {8 Name 80 3} {3 = 80 8} {4 "Kyle Gunger" 80 10} {0 ; 82 0} {3 ~ 82 1} {8 s1 82 2} {8 b 82 5} {3 = 82 7} {3 ~ 82 9} {8 a 82 10} {0 ; 83 0} {8 b 83 1} {3 ~ 83 2} {3 . 83 3} {8 Name 83 4} {0 ; 86 0} {8 s1 86 1} {8 c 86 4} {3 = 86 6} {2 { 86 8} {4 "" 86 9} {1 , 86 11} {4 "" 86 13} {2 } 86 15} {0 ; 90 0} {8 s1 90 1} {8 d 90 4} {2 { 90 5} {8 Message 91 4} {3 = 91 12} {4 "Message" 91 14} {1 , 91 23} {8 Name 92 4} {3 = 92 9} {4 "Name" 92 11} {2 } 93 0} {0 ; 99 0} {2 { 99 1} {2 } 99 2} {5 int 99 3} {8 a 99 7} {3 = 99 9} {2 { 99 11} {4 1, 100 2} {4 2, 100 6} {4 3, 100 10} {4 4 100 14} {2 } 101 0} {0 ; 104 0} {2 { 104 1} {2 } 104 2} {5 int 104 3} {8 a 104 7} {2 { 104 8} {4 1, 105 2} {4 2, 105 6} {4 3, 105 10} {4 4 105 14} {2 } 106 0} {2 /; 110 0} {8 s1 110 2} {2 [ 110 5} {8 s1 110 6} {2 ] 110 8} {8 return 112 2} {8 new 112 9} {8 s1 112 13} {2 { 112 15} {4 "Kyle" 112 16} {1 , 112 22} {4 "TNSL Creator" 112 24} {2 } 112 38} {2 ;/ 113 0} {2 /; 115 0} {7 if 115 3} {2 ( 115 6} {8 i 115 7} {3 == 115 9} {4 3 115 12} {2 ) 115 14} {2 ;; 118 0} {7 else 118 2} {2 ;/ 120 0} {2 /; 122 0} {7 switch 122 3} {2 ( 122 10} {8 i 122 11} {2 ) 122 12} {0 ; 124 2} {5 int 124 3} {8 t 124 7} {3 = 124 9} {4 0 124 11} {2 /; 127 2} {7 case 127 4} {4 1 127 9} {0 ; 128 4} {8 i 128 5} {3 = 128 7} {4 0 128 9} {0 ; 129 4} {8 t 129 5} {3 = 129 7} {4 2 129 9} {0 ; 130 4} {7 break 130 5} {2 ;; 132 2} {7 case 132 4} {4 2 132 9} {0 ; 133 4} {8 i 133 5} {3 = 133 7} {4 1 133 9} {0 ; 134 4} {8 t 134 5} {3 = 134 7} {4 2 134 9} {0 ; 135 4} {7 break 135 5} {2 ;; 137 2} {7 default 137 4} {0 ; 138 4} {8 i 138 5} {3 = 138 7} {4 3 138 9} {0 ; 139 4} {7 break 139 5} {2 ;/ 140 2} {2 /; 143 2} {7 if 143 5} {2 [ 143 8} {8 t 143 9} {3 == 143 11} {4 2 143 14} {2 ] 143 16} {0 ; 144 4} {8 i 144 5} {3 = 144 7} {8 t 144 9} {3 - 144 11} {8 i 144 13} {2 ;; 146 2} {7 else 146 4} {7 if 146 9} {2 [ 146 12} {8 t 146 13} {3 == 146 14} {4 3 146 16} {2 ] 146 18} {0 ; 147 4} {8 i 147 5} {3 = 147 7} {8 t 147 9} {3 + 147 10} {8 i 147 11} {2 ;/ 148 2} {2 /; 151 2} {7 case 151 4} {4 1 151 9} {0 ; 152 4} {8 i 152 5} {3 = 152 7} {4 4 152 9} {2 ;/ 153 2} {2 ;/ 154 0} {0 ; 158 0} {7 struct 158 2} {2 [ 158 9} {8 gen 158 10} {2 ] 158 13} {2 ( 158 15} {7 type 158 16} {8 T 158 21} {2 ) 158 22} {2 { 158 24} {8 T 159 2} {8 i 159 4} {2 } 160 0} {0 ; 163 0} {8 gen 163 1} {2 ( 163 4} {5 int 163 5} {2 ) 163 8} {8 j 163 10} {2 { 163 11} {4 2 163 12} {2 } 163 14} {0 ; 166 0} {2 { 166 1} {2 } 166 2} {8 gen 166 3} {2 ( 166 6} {8 gen 166 7} {2 ( 166 10} {5 int 166 11} {2 ) 166 14} {2 ) 166 15} {8 j 166 17} {2 { 166 18} {2 { 167 2} {2 { 167 3} {4 1 167 4} {2 } 167 6} {2 } 167 7} {1 , 167 8} {2 { 168 2} {2 { 168 3} {4 2 168 4} {2 } 168 6} {2 } 168 7} {1 , 168 8} {2 { 169 2} {2 { 169 3} {4 3 169 4} {2 } 169 6} {2 } 169 7} {2 } 170 0}]
\ No newline at end of file diff --git a/qualifiers.txt b/qualifiers.txt new file mode 100644 index 0000000..835a5f5 --- /dev/null +++ b/qualifiers.txt @@ -0,0 +1,71 @@ +block qualifier list: + +interface** +enum** +loop +match +if +else +method* +override* +raw +inline +export +module +case +default +operator* + + + +structure of blocks: + +(block start) + interface (defword) + enum (defword) (return type list) + + loop (bool params) (loop rets) + if (bool params) + else + if (bool params)*** + + match (match params) (case blocks) + case (case params) + default + + override*** + method (defword) (function params) (function rets) + operator <unary operator> (ret) + operator <binary operator> (param) (ret) + + export*** + module (defword) + + inline*** + raw*** + (defword) (function params) (function rets) +(block end) + + + +structure of statements: + +(type) (definition list) +(value) +(keyword) (parameters if required) + + + +keyword statements: + +delete (list of defwords)* +struct (defword) (struct params)* +continue +break +label (defword) +goto (defword) +asm (defstring) + +* - type extension +** - advanced type extension +*** - optional modifier diff --git a/base.tnsl b/small-tests/base.tnsl index f291cf3..f291cf3 100644 --- a/base.tnsl +++ b/small-tests/base.tnsl diff --git a/examp.tnsl b/small-tests/examp.tnsl index 0c32f3f..0c32f3f 100644 --- a/examp.tnsl +++ b/small-tests/examp.tnsl diff --git a/small-tests/out.tnt b/small-tests/out.tnt new file mode 100644 index 0000000..9f77b4b --- /dev/null +++ b/small-tests/out.tnt @@ -0,0 +1 @@ +{{9 test.tnsl 0 0} [{{10 block 0 0} [{{10 block 0 0} [{{11 ; 0 0} []} {{11 ; 0 0} []}]} {{10 block 0 0} [{{11 ; 0 0} []} {{11 ; 0 0} []}]} {{11 ; 0 0} []} {{11 ; 0 0} []}]} {{11 ; 0 0} []}]} diff --git a/small-tests/test.tnsl b/small-tests/test.tnsl new file mode 100644 index 0000000..f7c030c --- /dev/null +++ b/small-tests/test.tnsl @@ -0,0 +1,13 @@ +/; + /; + ; + ; + ;; + ; + ; + ;/ + ; + ; +;/ + +; thing
\ No newline at end of file diff --git a/spec/compiler/compiler.txt b/spec/compiler/compiler.txt index dbc64c0..df7a591 100644 --- a/spec/compiler/compiler.txt +++ b/spec/compiler/compiler.txt @@ -10,9 +10,14 @@ in their own file. 2) Validation - 2a) The expander - expands pre-processor commands and macrosoperations + 2a) The expander - expands pre-processor commands and macro operations 2b) The validator - checks all requirements for all functions and expressions are valid 3) Translation - 3a) ???
\ No newline at end of file + 3a) Variable resolver - chooses and creates an internal model of where variables are on the stack, as well as calling conventions for functions + 3b) Type translator - places and translates types (internal and external) + 3c) Container resolver - checks container (elf, exe, dll, app, out, etc.) and decides how to map the types for future linking + 3d) Final translation - translates all logic and expressions into native binary code + 3e) Optimization + 3f) Container Writer - writes the final output of the previous steps into the specified container diff --git a/spec/compiler/pre-processor.txt b/spec/compiler/pre-processor.txt index 3203ff8..8297e7d 100644 --- a/spec/compiler/pre-processor.txt +++ b/spec/compiler/pre-processor.txt @@ -2,4 +2,8 @@ A set of components in the compiler (all before the translator) which expand, resolve, and validate pre-processor directives into code which can be compiled Consists of the resolver in the parsor. -The expander and part of the indexer in the validator.
\ No newline at end of file +The expander and part of the indexer in the validator. + +Special (compiler specififc) definitions can be added with _<compiler>_<variable name> + +E.X. if the official implementation wanted to provide the exact time of the compilation, it could use _TNSLC_TIME_NOW for instance
\ No newline at end of file diff --git a/spec/iex/iex-spec.txt b/spec/iex/iex-spec.txt new file mode 100644 index 0000000..6979cfc --- /dev/null +++ b/spec/iex/iex-spec.txt @@ -0,0 +1,128 @@ +This is the IEX file specification. + +Document version (semver): 0.0.1 +Main Author: Kyle Gunger + +License: Apache 2.0 + +---------------------------------- + +Contents: + +Organization + +---------------------------------- + +Organization + +Magic number starts the file "IEX" or 0x49 0x45 0x58 + +The header of the file can be represented as such + +;struct IEX_HEAD { + raw {3}char # Always "IEX" + magic, + + {}char + name, + arch, + os, + + uint8 # Version info + major, + minor, + patch, + # OS abi info + os_major, + os_minor, + os_patch, + + bool # Tells loader that the file holds a main function + can_execute, + + ~void ({}{}char args) [int] + # Address of main in file + start_addr, + + {}IEX_SECTION + sections, + + {}IEX_LIB + dependencies, + + IEX_MODULE + self +} + +a section is defined as + +;struct IEX_SECTION { + {}char + name, + + uint8 # Denotes dependency, symbol table, data, bss, text, etc. + type, + + ~void # Points to start and end of section + start, + end +} + +;struct IEX_LIB { + {}char + name, + + uint8 # Version info + major, + minor, + patch +} + +;struct IEX_MODULE { + {}char + name, + + {}IEX_FUNCTION + func, + + {}IEX_TYPE + types, + + {}IEX_MODULE + sub +} + +;struct IEX_FUNCTION { + {}char + name, + + uint32 + overload, + bytes_in, + bytes_out, + + ~void + addr +} + +;struct IEX_TYPE { + {}char + name, + + bool + raw_struct, + interface, + dynamic, + + uint32 + size, + + {}IEX_FUNCTION + methods, + + {}IEX_TYPE + supers, + + ~void + addr +} diff --git a/spec/libts.txt b/spec/libts.txt index e69de29..e31d59d 100644 --- a/spec/libts.txt +++ b/spec/libts.txt @@ -0,0 +1,93 @@ +This is the LIBTS specification, a document related to the definition of the TNSL language, +meta-language, it's usage, and where it's standard libraries may be ported. + +Document version (semver): 0.0.1 +Main Author: Kyle Gunger + +License: Apache 2.0 + +---------------------------------- + +Contents: + +Part 1 -- About the Library + 1.1: libts and TNSL + 1.2: Short overview + +Part 2 -- Library Features + 2.1: Bitwise operations + 2.2: Standard algorithms + 2.3: Continer structs + 2.4: Standard abstractions + 2.5: Time related APIs + 2.6: Method resolution + +---------------------------------- + +Part 1: About the Library + +---------------------------------- + +Section 1: libts and TNSL + + libts or the TNSL standard library is a library to be found on almost all systems containing + a TNSL implimentation. The library contains both common APIs which ease common programming + feats as well as core program logic for the more high-level features of TNSL. TNSL can + indeed run without a libts, however doing so limits many parts of the language to the "raw" + variants. These limited features include structs, types, and interfaces primarially. + + libts contains a standard method resolution algorithm such that method calls can be resolved + on runtime for the high level dynamic type system. + +---------------------------------- + +Section 2: Short overview + + The library contains many standard algoritims and abstractions found in other languages such + as C, as well as helpers for these containers. + + +---------------------------------- + +Part 2: Library Features + +---------------------------------- + +Section 1: Bitwise Operations + +---------------------------------- + +Section 2: Standard algorithms + +---------------------------------- + +Section 3: Continer structs + +---------------------------------- + +Section 4: Standard abstractions + +---------------------------------- + +Section 5: Time related APIs + + Time is important for any program, and libts provides an interface through which to query + the operating system for it. libts also provides conversion, projection, and timing features + so that programs can make use of user inputs relating to time. If bugs in the time projection + of the library, they will be fixed. No reguard to existing data should be given, accuracy is + the goal above breakage. + + That being said, the library should attempt to work around erronious data in a way that + provides an alternative date if the data is in a good format but pointing to a non-existant + date. An error code will still be thrown in these cases, but indicating that the date does + not exist, not that the input was complete garbage. Programs may catch errors in any way + they choose. + +---------------------------------- + +Section 6: Method resolution + + As previously stated, the library performs method resolution for calls on high-level types. + In an iex file, this is done by finding the associated IEX_TYPE of the object and following + along the "supers" array and checking with the "methods" arrays until the IEX_TYPE contains + a definition for the method called which fits the caller's arguments.
\ No newline at end of file diff --git a/spec/spec.txt b/spec/spec.txt index 033bb32..4086d3c 100644 --- a/spec/spec.txt +++ b/spec/spec.txt @@ -87,7 +87,7 @@ Each file may contain 0 or more of the following: 6) Module blocks -Code blocks are the only blocks which may contain statements (1.3) +Code blocks and method blocks are the only blocks which may contain statements (1.3) and logical blocks. ---------------------------------- @@ -321,13 +321,19 @@ Statements make up the actual "doing" part of TNSL 1) Literal values Literal numbers start with a decimal number, and can contain up to one non-number element: - 0b1001 - valid 0 - valid 0.2341 - valid 120000 - valid .34567 - invalid - 0 + 0asd...kj - invalid + + Special bases: + + 0b1001 - valid (binary) + 0o0127 - valid (octal) + 0xABCD - valid (hex) + 0BZZZZ - valid (base 64) These rules will be ammended and are mostly for ease of parsing in the first version of the language. @@ -344,14 +350,24 @@ Statements make up the actual "doing" part of TNSL " - invalid Literal characters use '' and either an escape character or a single character/code point between them - + ' ' - valid + '\u2000' - valid + '\\' - valid + '\'' - valid + + invalid: + '\u200220202asdasdaw qwe ' + '\\asd asd ' + 'ab' + '\' + ' 2) Call with a return calling a function is as simple as naming a block of code and then calling it with parentheses # Define - /; add () + /; add ;/ # Call (not expression) @@ -403,8 +419,7 @@ Statements make up the actual "doing" part of TNSL 1.4: Types TNSL's type system consists of built-in types, user interfaces, and user structs. -The built-in types are always on the stack, while user types can be on the stack, on the heap, -or somewhere in between. +The built-in types are always on the stack, while user types can be on the stack or the heap. 1.4.1: Built-in types Built-in types are meant to be portable so that tnsl can be backported to whatever system one may want. @@ -453,20 +468,17 @@ or somewhere in between. uint64 - 64 bit unsigned int float64 - 64 bit floating point - simd (NICE): - not really sure how these work yet. I'll get back to you + vect (NICE): + vector, simd, etc. not really sure how these work yet. I'll get back to you size 128 (NICE): int128 uint128 float128 - comp128 - complex 128 bit (2 64 bit floats in a trenchcoat) 1.4.2: User defined types (stack) Any structs defined not using pointers are automatically allocated on the stack. - The meta type is really a pointer, and so structs using it will not be completely on - the stack. Structs are normally alligned to byte boundaries @@ -474,11 +486,11 @@ or somewhere in between. Defining a struct can be done as follows: - ;struct <struct name> ( <optional inputs> ) { <list of members (may use inputs)> } + ;struct <struct name> (<list of inputs (makes this a dynamic type)>) { <list of members (may use inputs)> } e.g. - ;struct Vector2 {x, y int32} + ;struct Vector2 {int32 x, y} Creating a variable from the struct can be done in two ways: @@ -501,14 +513,14 @@ or somewhere in between. method block example using operator - /; method ~Vector2 + /; method Vector2 - /; operator + (v ~Vector2) + /; operator + (~Vector2 v) ;self.x += `v.x ;self.y += `v.y ;/ - /; dot (v ~Vector2) [int32] + /; dot (~Vector2 v) [int32] ;return self.x * `v.x + self.y * `v.y ;/ @@ -605,12 +617,12 @@ and how functions are first-class in TNSL Anonymous blocks can be written only as scope, or with inputs and outputs for function calls. - /; call_func (to_call void(int32)[int32]) [int32] + /; call_func (void(int32)[int32] to_call) [int32] ;return to_call(5) ;/ /; provide_anon () [int32] - ;return call_func(/; (a int32) [int32] + ;return call_func(/; (int32 a) [int32] ;return a + 1 ;/) ;/ @@ -866,4 +878,51 @@ Augmented boolean operators (a !<op> b) = !(a <op> b) >== - Same as !< -<== - Same as !>
\ No newline at end of file +<== - Same as !> + +---------------------------------- + +Appendix C: Memory control (and speed) with each type of struct + +Each type of user-definable type or struct or interface grants +it's own level of memory control. These (and their ramifications) are +listed here from low to high. + +--- + +High level, low control structs (dynamic structs) are created when using +the parameters for structs/types. They allow variable length which can +house different information at the cost of speed, memory, and control. + +These are the only type of structs which can house other dynamic structs. +Dynamic structs can only be passes by reference due to undefined size at +compilation. + +--- + +Medium level, medium control structs (type structs) are created normaly +through the struct keyword without parameters. These structs are fixed +length, but the compiler encodes extra info into them. This means they +get method resolution and override checks which may reduce speed of the +application. + +--- + +Low level, high control structs (raw structs) are created using the "raw" +keyword before the "struct" keyword. There are no frills, and method +resolution is not performed for these structs. These structs may not +extend or be extended. They may, however, implement interfaces. They +perform as a "what you see is what you get" kind of memory model. They +may not use parameters, and all internal types must be consistant length +(no dynamic structs or dynamic type identifiers). + +--- + +To summerize: +All these structs can encode the same info, but as you get lower to +the system, you get the bonus of speed and control while losing higher +level functions provided by the language. + +This shouldn't matter much to most programmers unless they are doing +embedded development, systems programming, or firmware programming, +but it is still a consideration to make for time-sensitive applications.
\ No newline at end of file diff --git a/src/main.go b/src/main.go index c74d0cb..e6efcd9 100644 --- a/src/main.go +++ b/src/main.go @@ -37,7 +37,7 @@ func main() { tokens := tparse.TokenizeFile(*inputFile) tree := tparse.MakeTree(&tokens, *inputFile) - fd.WriteString(fmt.Sprint(tree)) + fd.WriteString(fmt.Sprint(tree) + "\n") fd.Close() } diff --git a/src/tparse/resolver.go b/src/tparse/resolver.go deleted file mode 100644 index 5267887..0000000 --- a/src/tparse/resolver.go +++ /dev/null @@ -1,24 +0,0 @@ -/* - Copyright 2020 Kyle Gunger - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package tparse - -//TODO: Everything - -/* - This file is support code to include other files when asked, and represents the most important part of the pre-processor - Maybe we will do this when writing the native compiler though -*/ diff --git a/src/tparse/tree-list.go b/src/tparse/tree-list.go index 78e45a8..843ca9b 100644 --- a/src/tparse/tree-list.go +++ b/src/tparse/tree-list.go @@ -32,7 +32,7 @@ func getClosing(start string) string { // Parse a list of values func parseValueList(tokens *[]Token, tok, max int) (Node, int) { out := Node{} - out.Data = Token{Type: 10, Data: "list"} + out.Data = Token{Type: 10, Data: "value"} var tmp Node c := getClosing((*tokens)[tok].Data) @@ -58,48 +58,9 @@ func parseValueList(tokens *[]Token, tok, max int) (Node, int) { return out, tok } -// Parses a list of definitions -func parseDefList(tokens *[]Token, tok, max int) (Node, int) { - out := Node{} - out.Data = Token{Type: 9, Data: "list"} - - currentType := Node{} - currentType.Data = Token{Data: "undefined"} - - c := getClosing((*tokens)[tok].Data) - - tok++ - - for ; tok < max; tok++ { - switch (*tokens)[tok].Data { - case c: - return out, tok - case ",": - tok++ - default: - errOut("Unexpected token when reading parameter definition", (*tokens)[tok]) - } - - t := (*tokens)[tok+1] - - if t.Data != "," && t.Data != c { - currentType, tok = parseType(tokens, tok, max, true) - } - - t = (*tokens)[tok] - - if t.Type != DEFWORD { - errOut("Unexpected token in parameter definition. Expected variable identifier", t) - } - - } - - return out, tok -} - func parseTypeList(tokens *[]Token, tok, max int) (Node, int) { out := Node{} - out.Data = Token{Type: 9, Data: "list"} + out.Data = Token{Type: 10, Data: "type"} var tmp Node c := getClosing((*tokens)[tok].Data) @@ -127,7 +88,7 @@ func parseTypeList(tokens *[]Token, tok, max int) (Node, int) { func parseStatementList(tokens *[]Token, tok, max int) (Node, int) { out := Node{} - out.Data = Token{Type: 9, Data: "list"} + out.Data = Token{Type: 10, Data: "statement"} var tmp Node c := getClosing((*tokens)[tok].Data) diff --git a/src/tparse/tree-statement.go b/src/tparse/tree-statement.go index f6d3452..938e827 100644 --- a/src/tparse/tree-statement.go +++ b/src/tparse/tree-statement.go @@ -18,24 +18,55 @@ package tparse func parseBlock(tokens *[]Token, tok, max int) (Node, int) { out := Node{} - out.Data = Token{Type: 9, Data: "list"} + out.Data = Token{Type: 10, Data: "block"} var tmp Node tok++ - for ; tok < max; tok++ { + for ;tok < max; tok++{ + t := (*tokens)[tok] + + switch t.Type { + case DELIMIT: + if t.Data == "(" { + + } else if t.Data == "(" { + + } else { + goto BREAK + } + case DEFWORD: + case KEYWORD: + case LINESEP: + goto BREAK + } + } + + BREAK: + + for ;tok < max; { t := (*tokens)[tok] switch t.Data { - case ")", "]", "}": + case ";/", ";;", ";:": return out, tok - case ",": - tok++ + case ";": + tmp, tok = parseStatement(tokens, tok, max) + case "/;": + REBLOCK: + + tmp, tok = parseBlock(tokens, tok, max) + + if (*tokens)[tok].Data == ";;" { + out.Sub = append(out.Sub, tmp) + goto REBLOCK + } else if (*tokens)[tok].Data == ";/" { + tok++ + } default: - errOut("Error: unexpected token when parsing a list of types", t) + errOut("Error: unexpected token when parsing a code block", t) } - tmp, tok = parseType(tokens, tok, max, true) out.Sub = append(out.Sub, tmp) } @@ -44,7 +75,7 @@ func parseBlock(tokens *[]Token, tok, max int) (Node, int) { func parseStatement(tokens *[]Token, tok, max int) (Node, int) { out := Node{} - out.Data = Token{Type: 9, Data: "list"} + out.Data = Token{Type: 11, Data: ";"} var tmp Node tok++ @@ -52,10 +83,10 @@ func parseStatement(tokens *[]Token, tok, max int) (Node, int) { for ; tok < max; tok++ { t := (*tokens)[tok] - switch t.Data { - case ")", "]", "}": + switch t.Type { + case LINESEP, DELIMIT: return out, tok - case ",": + case INLNSEP: tok++ default: errOut("Error: unexpected token when parsing a list of types", t) @@ -70,7 +101,7 @@ func parseStatement(tokens *[]Token, tok, max int) (Node, int) { func parseDef(tokens *[]Token, tok, max int) (Node, int) { out := Node{} - out.Data = Token{Type: 9, Data: "list"} + out.Data = Token{Type: 10, Data: "list"} var tmp Node tok++ diff --git a/src/tparse/tree-value.go b/src/tparse/tree-value.go index 1a057d4..d03383e 100644 --- a/src/tparse/tree-value.go +++ b/src/tparse/tree-value.go @@ -16,6 +16,74 @@ package tparse +// Ops order in TNSL +// Cast/Paren > Address > Get > Inc/Dec > Math > Bitwise > Logic + +var ORDER = map[string]int{ + // Address of + "~": 0, + // De-ref + "`": 0, + + // Get + ".": 1, + + // Inc/Dec + "++": 2, + "--": 2, + + // Multiplication + "*": 3, + // Division + "/": 3, + + // Addition + "+": 4, + // Subtraction + "-": 4, + + // Mod + "%": 5, + + // Bitwise and + "&": 6, + // Bitwise or + "|": 6, + // Bitwise xor + "^": 6, + + // Bitwise l-shift + "<<": 6, + // Bitwise r-shift + ">>": 6, + + "!&": 6, + "!|": 6, + "!^": 6, + + // Not (prefix any bool or bitwise) + "!": 6, + + // Boolean and + "&&": 7, + // Boolean or + "||": 7, + // Truthy equals + "==": 7, + + // Greater than + ">": 7, + // Less than + "<": 7, + + "!&&": 7, + "!||": 7, + "!==": 7, + + "!>": 7, + "!<": 7, +} + func parseValue(tokens *[]Token, tok, max int) (Node, int) { out := Node{} @@ -33,9 +101,48 @@ func parseValue(tokens *[]Token, tok, max int) (Node, int) { func parseVoidType(tokens *[]Token, tok, max int) (Node, int) { out := Node{} + working := &out for ; tok < max; tok++ { - //t := (*tokens)[tok] + t := (*tokens)[tok] + switch t.Type { + case AUGMENT: + if t.Data != "~" && t.Data != "`" { + errOut("Error: unexpected augment token when parsing type", t) + } + working.Data = t + + case KEYTYPE: + if t.Data == "void" { + *working, tok = parseVoidType(tokens, tok, max) + } else { + working.Data = t + } + + return out, tok + + case DEFWORD: + + case DELIMIT: + if t.Data == "{" && tok < max-1 { + if (*tokens)[tok+1].Data == "}" { + working.Data = Token{AUGMENT, "{}", t.Line, t.Char} + tok++ + } else { + errOut("Error: start of list when parsing type (did you mean \"{}\"?)", t) + } + } else if tok >= max-1 { + errOut("Error: unexpected end of file when parsing type", t) + } else { + errOut("Error: unexpected delimeter when parsing type", t) + } + + default: + errOut("Error: unexpected token when parsing type", t) + } + + makeParent(working, Node{}) + working = &(working.Sub[0]) } return out, tok @@ -49,7 +156,7 @@ func parseType(tokens *[]Token, tok, max int, param bool) (Node, int) { t := (*tokens)[tok] switch t.Type { case AUGMENT: - if t.Data != "~" { + if t.Data != "~" && t.Data != "`" { errOut("Error: unexpected augment token when parsing type", t) } working.Data = t @@ -70,22 +177,33 @@ func parseType(tokens *[]Token, tok, max int, param bool) (Node, int) { case KEYWORD: if param && t.Data == "static" { + // Nonstandard keyword in parameter definition errOut("Error: parameter types cannot be static", t) } else if t.Data != "const" && t.Data != "volatile" && t.Data != "static" { + // Nonstandard keyword in variable definition errOut("Error: unexpected keyword when parsing type", t) } working.Data = t case DELIMIT: - if t.Data == "{" { + if t.Data == "{" && tok < max-1 { + // What happens when an array type is defined if (*tokens)[tok+1].Data == "}" { - working.Data = Token{9, "array", t.Line, t.Char} + // Length variable array + working.Data = Token{AUGMENT, "{}", t.Line, t.Char} tok++ + } else if (*tokens)[tok+1].Type == LITERAL { + // Array with constant length } else { - errOut("Error: start of list when parsing type (did you mean {} ?)", t) + // Undefined behaviour + errOut("Error: start of list when parsing type (did you mean \"{}\"?)", t) } + } else if tok >= max-1 { + // End of file with open delimiter after type parsing has begun + errOut("Error: unexpected end of file when parsing type", t) } else { - errOut("Error: start of list when parsing type", t) + // Other delimiter than {} used in variable definition + errOut("Error: unexpected delimeter when parsing type", t) } default: diff --git a/src/tparse/tree.go b/src/tparse/tree.go index 0b7baf4..9e9e554 100644 --- a/src/tparse/tree.go +++ b/src/tparse/tree.go @@ -18,7 +18,8 @@ package tparse import "fmt" -// ID 9 = ast thing +// ID 9 = ast root +// ID 10 = ast list func errOut(message string, token Token) { fmt.Println(message) @@ -32,7 +33,6 @@ func MakeTree(tokens *[]Token, file string) Node { out.Data = Token{9, file, 0, 0} tmp := Node{} - working := &tmp max := len(*tokens) @@ -40,19 +40,18 @@ func MakeTree(tokens *[]Token, file string) Node { t := (*tokens)[tok] switch t.Data { case "/;": - + tmp, tok = parseBlock(tokens, tok, max) case ";": - + tmp, tok = parseStatement(tokens, tok, max) case "/:": - + tmp = Node{} case ":": - + tmp = Node{} default: errOut("Unexpected token in file root", t) } - tmp = Node{Data: t} - working.Sub = append(working.Sub, tmp) + out.Sub = append(out.Sub, tmp) } return out diff --git a/src/tparse/type.go b/src/tparse/type.go index 70d8776..73bb94d 100644 --- a/src/tparse/type.go +++ b/src/tparse/type.go @@ -50,8 +50,11 @@ var PREWORDS = []string{ "extern", "size", "align", + "origin", + "rootfile", "if", "else", + "abi", //"mark", } @@ -128,7 +131,7 @@ var RESWORD = map[string]int{ "module": KEYWORD, "export": KEYWORD, - "_": KEYWORD, + "drop": KEYWORD, } func checkResWord(s string) int { diff --git a/tests/block-test.tnsl b/tests/block-test.tnsl index 9f25526..6dde05f 100644 --- a/tests/block-test.tnsl +++ b/tests/block-test.tnsl @@ -46,15 +46,22 @@ /; module vec - ;struct Vector2 {x, y int} + ;struct Vector2 {int32 x, y} - /;method ~Vector2 + /;method Vector2 - /; operator + (v ~Vector2) + /; operator + (~Vector2 v) ;self.x += `v.x ;self.y += `v.y ;/ + /; operator + (int32 a) + ;self.x += a + ;self.y += a + ;/ + ;/ + ;struct FVector2 () {} + ;/
\ No newline at end of file diff --git a/tests/parameter-test.tnsl b/tests/parameter-test.tnsl index 2c39cb9..254db75 100644 --- a/tests/parameter-test.tnsl +++ b/tests/parameter-test.tnsl @@ -14,5 +14,5 @@ limitations under the License. #/ -/; loop (int initial = 0, int complex = 2) [initial < max || complex < 40, initial++, complex += 7, another += 2] +/; loop (int initial = 0, complex = 2) [initial < max || complex < 40, initial++, complex += 7, another += 2] ;/ diff --git a/tests/run-tests.sh b/tests/run-tests.sh index 2443823..6cebbe7 100755 --- a/tests/run-tests.sh +++ b/tests/run-tests.sh @@ -2,17 +2,11 @@ PARSECMD=../build/parse PARSEFILE=" " parse () { - $PARSECMD -in $PARSEFILE-test.tnsl -out $PARSEFILE-test.tnt + $PARSECMD -in $1-test.tnsl -out $1-test.tnt } -PARSEFILE=block -parse - -PARSEFILE=comment -parse - -PARSEFILE=literal -parse - -PARSEFILE=parameter -parse
\ No newline at end of file +parse block +parse comment +parse literal +parse parameter +parse statement
\ No newline at end of file diff --git a/tests/statement-test.tnsl b/tests/statement-test.tnsl new file mode 100644 index 0000000..71bd64b --- /dev/null +++ b/tests/statement-test.tnsl @@ -0,0 +1,6 @@ +/; small_block +;/ + +/; if_block +;; else_block +;/
\ No newline at end of file |