├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── TODO ├── deps └── llvm │ ├── README │ └── configure.sh ├── examples ├── parse.cc ├── program1.hue ├── program10-data-literals.hue ├── program10.x64.asm ├── program11-lists.hue ├── program2-multi-line-func-body.hue ├── program3-eq.hue ├── program4-func-params.hue ├── program5-bool.hue ├── program6-putchar.hue ├── program7-fib.hue ├── program8-if-then-else.hue ├── program9-number-literals.hue └── tokenize.cc ├── src ├── DebugTrace.h ├── Logger.cc ├── Logger.h ├── Mangle.cc ├── Mangle.h ├── Text.cc ├── Text.h ├── ast │ ├── BinaryOp.h │ ├── Block.h │ ├── Call.h │ ├── Conditional.h │ ├── DataLiteral.h │ ├── Expression.h │ ├── Function.h │ ├── FunctionType.cc │ ├── FunctionType.h │ ├── ListLiteral.h │ ├── Node.h │ ├── StructType.cc │ ├── StructType.h │ ├── Structure.cc │ ├── Structure.h │ ├── Symbol.cc │ ├── Symbol.h │ ├── TextLiteral.h │ ├── Type.cc │ ├── Type.h │ ├── Variable.h │ └── ast.h ├── codegen │ ├── Visitor.cc │ ├── Visitor.h │ ├── _VisitorImplFooter.h │ ├── _VisitorImplHeader.h │ ├── assignment.cc │ ├── binop.cc │ ├── call.cc │ ├── cast.cc │ ├── conditional.cc │ ├── data_literal.cc │ ├── function.cc │ ├── function_type.cc │ ├── structure.cc │ ├── symbol.cc │ ├── text_literal.cc │ └── type_conversion.cc ├── fastcmp.h ├── linenoise │ ├── .gitignore │ ├── Makefile │ ├── README.markdown │ ├── example.c │ ├── linenoise.cc │ └── linenoise.h ├── main.cc ├── parse │ ├── ByteInput.h │ ├── FileInput.h │ ├── Parser.h │ ├── StreamInput.h │ ├── Token.h │ ├── TokenBuffer.h │ └── Tokenizer.h ├── runtime │ ├── Vector.cc │ ├── Vector.h │ ├── object.h │ ├── runtime.cc │ └── runtime.h ├── termstyle.h ├── transform │ ├── LazyFuncResultTransformer.h │ ├── Scope.cc │ └── Scope.h └── utf8 │ ├── LICENSE │ ├── checked.h │ ├── core.h │ └── unchecked.h └── test ├── test_factorial.hue ├── test_func_fib.hue ├── test_func_inferred_result_type.hue ├── test_lang_bools.hue ├── test_lang_conditionals.hue ├── test_lang_data_literals.hue ├── test_lang_funcs.hue ├── test_mangle.cc ├── test_object.cc ├── test_struct.hue ├── test_vector.cc └── test_vector_perf.cc /.gitignore: -------------------------------------------------------------------------------- 1 | *.a.s 2 | *.a 3 | *.o 4 | *.hue.ll 5 | *.hue.img 6 | *. 7 | .hue_history 8 | 9 | build 10 | test/build 11 | 12 | deps/llvm/src 13 | deps/llvm/build 14 | deps/llvm/bin 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The Hue project contains some 3rd party software: 2 | 3 | - UTF8CPP: License can be found in src/utf8/LICENSE 4 | - linenoise: License can be found in src/linenoise/linenoise.h 5 | 6 | Unless otherwise stated, this software and associated documentation files are subject to the following license: 7 | 8 | Copyright (c) 2012 Rasmus Andersson 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | # TODO 2 | 3 | • Rudimentary structures (to get something started and we will 4 | iterate later) 5 | 6 | • Macros 7 | 8 | unless = macro test a b -> if %test %b else %a 9 | foo1 = unless (4 < 5) 100 200 10 | foo2 = if (4 < 5) 200 else 100 11 | 12 | • List literals (underlying impl is the persistent vector) 13 | 14 | • Records 15 | 16 | foo = { 17 | bar = 1234 18 | baz = { 19 | hello = "Hello" 20 | grok = ^(s Text) Text: Text:toUpper s 21 | } 22 | } 23 | foo:bar == 1234 24 | foo:bar:baz:hello == "Hello" 25 | (foo:bar:baz:grok "hello") == "HELLO" 26 | 27 | • Conceptual: Should we have the notion of invoking functions "on" something 28 | or stricly "with" something? 29 | 30 | A: foo = "Hello"; foo2 = foo.cat " World" 31 | B: foo = "Hello"; foo2 = cat foo " World" 32 | A: foo = [1 2 3]; L = foo.length 33 | B: foo = [1 2 3]; L = length foo 34 | A: foo = bar.firstItem().length.hexadecimal 35 | B: foo = hexadecimal (length (firstItem bar)) 36 | A: foo = bar.magicDistance 123 37 | B: foo = Bar:magicDistance bar 123 38 | 39 | I think B is better as it makes it even more clear that functions take 40 | state (they don't have state). 41 | 42 | • List slices 43 | 44 | foo = [1 2 3 4 5] 45 | bar = foo[1:] == [2 3 4 5] 46 | 47 | Simply a composite type (no copy needed since it's only referencing something) 48 | struct slice { 49 | const vector vec // must hold a reference 50 | const int start 51 | const int end 52 | } 53 | 54 | • Closures — functions that capture their environment 55 | 56 | Here, firstChar is captured by ^(Char)Char: 57 | 58 | foo = ^(s Text) Text: 59 | firstChar = s[:1] 60 | map s ^(c Char) Char: firstChar 61 | 62 | On the same note, here's a fun function: 63 | 64 | Elegant Clojure "blank?" function which checks to see whether a string is blank: either empty or consisting of only whitespace. 65 | (defn blank? [s] (every? #(Character/isWhitespace %) s)) 66 | 67 | Hue equivalent: 68 | blank? = ^(s Text) Bool: every? Character:isWhitespace s 69 | 70 | The every? function takes a function and a collection as its arguments and returns true if that function returns true for every item in the collection. 71 | 72 | • Types 73 | 74 | Name = type Text 75 | User = type {id Int, name Text} 76 | 77 | • Refs — mutable containers providing transactions 78 | 79 | User = type {id Int, name Text} 80 | users = Ref [User] 81 | # users => [] 82 | update users append User {id = 1, name = "Bart"} 83 | # users => [User{id = 1, name = "Bart"}] 84 | update users append User {id = 2, name = "Lisa"} 85 | # users => [User{id = 1, name = "Bart"}, User{id = 2, name = "Lisa"}] 86 | userList = deref users 87 | # userList => [User{id = 1, name = "Bart"}, User{id = 2, name = "Lisa"}] 88 | set users [] 89 | # users => [] 90 | # userList => [User{id = 1, name = "Bart"}, User{id = 2, name = "Lisa"}] 91 | 92 | Does this mean we need something similar to C++ templates, so that `Ref [User]` can be possible? And what about `deref`? It needs to know the type of the ref. One way to do this it not to do it, by implementing this stuff in the compiler as a special case. In that case, should Ref have a special name, perhaps "$" or "~"? 93 | 94 | • Exporting of things from modules 95 | 96 | Move export style: 97 | 98 | pow = func (n Int) -> Int n * n 99 | bar = 123 100 | export pow bar 101 | 102 | Or perhaps a top-of-module "exports"? (Becomes tedious but obvious) 103 | 104 | exports 105 | pow func (n Int) -> Int 106 | bar Int 107 | 108 | • Require/use instead of external functions makes everything cleaner. 109 | 110 | require hue:io hue:text 111 | hue:io:println (hue:text:toUpper "Hello") 112 | 113 | use hue:io hue:text 114 | println (toUpper "Hello") 115 | 116 | Or "import" style? 117 | 118 | io = import hue:io 119 | txt = import hue:text 120 | io:println (txt:toUpper "Hello") 121 | 122 | The runtime library, and any extensions, need to explicitly export their functions instead of just defining them. 123 | 124 | using namespace hue; 125 | Vector* toUpper(Vector* text) { ... } 126 | void hue_init(Env* env) { 127 | Module* m = env->getModule("text"); // get or create 128 | Func* fun = Func::create(toUpper); 129 | fun->result = Type(Type::Vector, Type(Type::Char)); 130 | fun->arguments.push_back( Type(Type::Vector, Type(Type::Char)) ); 131 | m->export("toUpper", fun); 132 | env->export(m); 133 | } 134 | 135 | • Simple API 136 | 137 | parse text -> program 138 | eval program -> result 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /deps/llvm/README: -------------------------------------------------------------------------------- 1 | 1. Grab LLVM sources: 2 | 3 | svn checkout http://llvm.org/svn/llvm-project/llvm/tags/RELEASE_30/final src 4 | 5 | 3. Run the magical configure.sh 6 | 7 | ./configure.sh 8 | 9 | 4. Build: 10 | 11 | cd build 12 | make -j 13 | 14 | 5. LLVM should have been built into the "build" subdirectory and 15 | installed in the "bin" subdirectory. 16 | -------------------------------------------------------------------------------- /deps/llvm/configure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "$(dirname $0)" 3 | LLVM_PROJECT_DIR="$(pwd)" 4 | LLVM_SRC_DIR="$LLVM_PROJECT_DIR/src" 5 | LLVM_DST_DIR="$LLVM_PROJECT_DIR/bin" 6 | LLVM_BUILD_DIR="$LLVM_PROJECT_DIR/build" 7 | 8 | cd "$LLVM_BUILD_DIR" 9 | 10 | "$LLVM_SRC_DIR/configure" \ 11 | "--prefix=$LLVM_DST_DIR" \ 12 | --enable-optimized \ 13 | --enable-jit \ 14 | --enable-targets=x86,x86_64 15 | 16 | #make -j 17 | -------------------------------------------------------------------------------- /examples/parse.cc: -------------------------------------------------------------------------------- 1 | // Parses a program into an Abstract Syntax Tree (AST). 2 | // 3 | // clang++ -std=c++11 -o build/example-parse examples/parse.cc \ 4 | // -Ibuild/include -Lbuild/lib -lhuert && build/example-parse 5 | // 6 | #include "../src/parse/FileInput.h" 7 | #include "../src/parse/Tokenizer.h" 8 | #include "../src/parse/TokenBuffer.h" 9 | #include "../src/parse/Parser.h" 10 | 11 | #include 12 | 13 | using namespace hue; 14 | 15 | int main(int argc, char **argv) { 16 | // Read input file 17 | Text textSource; 18 | const char* filename = argc > 1 ? argv[1] : "examples/program1.hue"; 19 | if (!textSource.setFromUTF8FileContents(filename)) { 20 | std::cerr << "Failed to read file '" << filename << "'" << std::endl; 21 | return 1; 22 | } 23 | 24 | // A tokenizer produce tokens parsed from a ByteInput 25 | Tokenizer tokenizer(textSource); 26 | 27 | // A TokenBuffer reads tokens from a Tokenizer and maintains limited history 28 | TokenBuffer tokens(tokenizer); 29 | 30 | // A parser reads the token buffer and produces an AST 31 | Parser parser(tokens); 32 | 33 | // Parse the input into an AST 34 | ast::Function *module = parser.parseModule(); 35 | 36 | // Check for errors 37 | if (!module) { 38 | std::cerr << "Failed to parse module." << std::endl; 39 | return 1; 40 | } else if (parser.errors().size() != 0) { 41 | std::cerr << parser.errors().size() << " errors." << std::endl; 42 | return 1; 43 | } 44 | 45 | // Print a textual representation of the AST 46 | std::cout << "\e[32;1mParsed module:\e[0m " << module->toString() << std::endl; 47 | 48 | return 0; 49 | } -------------------------------------------------------------------------------- /examples/program1.hue: -------------------------------------------------------------------------------- 1 | # A function declaration 2 | A = extern atan2 (a Float, b Float) Float 3 | B Float = A 1.1 2.2 4 | C = ^(x Float, y Float) Float: A 3.3 4.4 5 | D Float = C 5.5 6.6 6 | 7 | E MUTABLE = ^(x Float, y Float) Float: C 7.7 8.8 8 | F Float = E 9.0 10.0 9 | X MUTABLE = F * A 4.5 2.3 10 | 11 | E = ^(x Float, y Float) Float: C 77.0 88.0 12 | F2 Float = E 9.1 X 13 | 14 | # Next up: Allow more than one expression in a function body 15 | G = ^(x Int) Int: 16 | y = x * 9 \ # ... Do not stop at the next NewLine 17 | + 5 # expr: y = x * 9 + 5 18 | y / 4 - 92 # return: expr: y / 4 - 92 19 | 20 | H = G 45 21 | 22 | 23 | # Todo: Control flow: if 24 | # Todo: Control flow: for 25 | # Todo: Control flow: while 26 | 27 | 28 | #E Float = D 3.1 # Should fail since D is not a callable 29 | 30 | ## A function definition 31 | #foo = func (x, y Float) Float -> 7.2 * x 32 | ## 6 + x + foo 5 (foo y 4.0) 33 | # 34 | #bar = func (x Float, y Float) Float -> math_atan2 12.0 7.2 * x 35 | # 36 | ## Call the foo function with a number argument of 40 37 | #M = foo 1.0 (bar 2.0 1.2) 38 | # 39 | ## Alias 1983 as "Year" 40 | #Year = 1983 41 | ##x = 4.9 42 | ##y = 3.1 + atan2 x 0.3 43 | #Month = Year + M 44 | # 45 | ##Day MUTABLE = foo 3.1 4.1 46 | # 47 | ##x Int, y MUTABLE, z MUTABLE Float = ninja2000 34.4 48 | ##MUTABLE y = 8 49 | ## todo: (foo 10 (foo (foo 20 40) 30)) to express foo(10,foo(foo(20,40),30)) 50 | -------------------------------------------------------------------------------- /examples/program10-data-literals.hue: -------------------------------------------------------------------------------- 1 | WriteData = extern _ZN3hue12stdout_writeEPNS_10ByteArray_E (data [Byte]) 2 | WriteText = extern _ZN3hue12stdout_writeEPNS_5Text_E (text [Char]) 3 | #WriteData = extern hue_stdout_write (data [Byte]) 4 | #WriteText = extern hue_stdout_write_text (text [Char]) 5 | data1 = 'Hello World\n' # T = [Byte] 6 | text1 = "Hello World\n" # T = [Char] 7 | WriteData data1 8 | WriteText text1 9 | -------------------------------------------------------------------------------- /examples/program10.x64.asm: -------------------------------------------------------------------------------- 1 | ## x86_64 assembler generated by llc -asm-verbose from the following program: 2 | ## 3 | ## Write = extern hue_stdout_write (data [Byte]) 4 | ## Data = 'Hello World\n' 5 | ## Write Data 6 | ## 7 | ## Executable 8 | .section __TEXT,__text,regular,pure_instructions 9 | .globl _main 10 | .align 4, 0x90 11 | 12 | ## Our main() function 13 | _main: 14 | pushq %rax ## Push a 64-bit register to the stack 15 | leaq L_ai8s(%rip), %rdi ## Load effective address of ai8s (our [Byte] object) to register %rdi 16 | ## %rip = Instruction Pointer 17 | ## %rdi = First argument to upcoming func call 18 | 19 | callq _hue_stdout_write ## Push the current address to the stack and call hue_stdout_write() 20 | xorl %eax, %eax ## Set the return value to 0 21 | popq %rdx ## Pop the return value into %rdx 22 | ret ## Return from main() 23 | 24 | ## Constant data 25 | .section __TEXT,__const 26 | L_ai8s: ## This is our [Byte] constant. Cove generated a struct: 27 | .quad 12 ## i64 length 28 | .ascii "Hello World\n" ## i8 x bytes 29 | 30 | .subsections_via_symbols 31 | -------------------------------------------------------------------------------- /examples/program11-lists.hue: -------------------------------------------------------------------------------- 1 | #listOfBools [Bool] = [] 2 | listOfInts = [123 456 789] 3 | 4 | list2 = (cat listOfInts [100 200 300]) 5 | #listOfText = ["Foo" "Bar"] # T = [[Char]] 6 | 7 | struct ListLink { 8 | T value 9 | struct ListLink* next 10 | } 11 | a = [100] => ListLink@1 { 100, 0 } 12 | b = [200] => ListLink@2 { 200, 0 } 13 | c = cat a b => ListLink@3 { 100, &b } 14 | d = [300, 400] => ListLink@5 { 300, ListLink@4 { 400, 0 } } 15 | c = cat c d => ListLink@6 { 100, &b } 16 | # ---------- 17 | List { 18 | List* prev 19 | T value 20 | List* next 21 | } 22 | a = [1 2 3] => 23 | a2 = List{ &a1, 3, nil } 24 | a1 = List{ &a0, 2, &a2 } 25 | a = List{ nil, 1, &a1 } # T = Int 26 | 27 | b = [4 5] => List{ 2, 4, 5 } # T = Int 28 | c = cat a b => List{ 2, &a, &b } # T = List* 29 | d = [6 7] => List{ 2, 6, 7 } # T = Int 30 | e = cat c d => List{ 2, &c, &d } # T = List* 31 | 32 | f = for item in e: 33 | item + 100 34 | 35 | for_func = ^(L): if ((L type) == List) .. 36 | # ---------- 37 | List { 38 | i32 count 39 | T value, ... 40 | } 41 | 42 | a = [1 2 3] => List{ 3, 1, 2, 3 } 43 | b = [4 5] => List{ 2, 4, 5 } 44 | c = cat a b => List{ 5, 1, 2, 3, 4, 5 } # copy :( 45 | d = [6 7] => List{ 2, 6, 7 } 46 | e = cat c d => List{ 2, &c, &d } 47 | # ------------ 48 | # Lists are always constant (but values themselves may be mutable) and has values or a diffptr. 49 | # See: http://www.linuxjournal.com/article/6828 "A Memory-Efficient Doubly Linked List" 50 | # Empty list = [] = ( length==0 && ptrdiff==nil ) 51 | # Length = list:length + () 52 | List { 53 | List* ptrdiff 54 | i64 length 55 | T value, ... 56 | } 57 | c = [] => { nil, 0 } 58 | a = [1 2 3] => { nil, 3, 1, 2, 3 } 59 | b = [4 5] => { nil, 2, 4, 5 } 60 | c = a & b => { a XOR b, 0 } 61 | d = [6 7] => { nil, 2, 6, 7 } 62 | e = c & d => { c XOR d, 0 } 63 | f = [8 9] & e => { nil XOR e, 2, 8, 9 } # constant folding 64 | g = [1 2 3] & [4 5 6] => { nil, 6, 1, 2, 3, 4, 5, 6 } # constant folding 65 | h = f & [10 11] => { f XOR nil, 2, 10, 11 } 66 | # Becomes quite expensive to iterate h, since we would need to first perform an ascent 67 | # to the root (a), keep state of that ascent, then iterate forward. Maybe it's acceptable. 68 | # ------------ 69 | # Second take on the above. Adds 64 bit per link, but makes forward iteration constant 70 | # complexity. Slightly more expensive on insert. 71 | List { 72 | List* header 73 | List* ptrdiff 74 | i64 length 75 | T value, ... 76 | } 77 | _ = [] => { self, nil, 0 } 78 | a = [1 2 3] => { self, nil, 3, 1, 2, 3 } 79 | b = [4 5] => { self, nil, 2, 4, 5 } 80 | c = a & b => { a:head, a XOR b, 0 } 81 | d = [6 7] => { self, nil, 2, 6, 7 } 82 | e = c & d => { c:head, c XOR d, 0 } 83 | f = [8 9] & e => { self, nil XOR e, 2, 8, 9 } 84 | g = [1 2 3] & [4 5 6] => { self, nil, 6, 1, 2, 3, 4, 5, 6 } 85 | h = f & [10 11] => { f:head, f XOR nil, 2, 10, 11 } 86 | # - To start iterate L, simply start at L:head||L and traverse. 87 | # - To start iterating backwards on L, start at end of L (item L:length-1) 88 | # and traverse ptrdiff (prev XOR). 89 | 90 | # 91 | # ------------ 92 | # Map? LUA style? 93 | Map { 94 | } 95 | a = [1 2 3] = {0:1 1:2 2:3} 96 | b = {one:1 two:2 three:3} 97 | a[0] = b[one] = 1 98 | 99 | # ------------ 100 | # Doubly-linked list 101 | List { 102 | T value 103 | List* prev 104 | List* next 105 | } 106 | a = [1 2 3] => 107 | a3 = { 3, nil, nil } 108 | a2 = { 2, &a3, nil } 109 | a1 = { 1, &a2, nil } 110 | a3:prev = &a2 111 | a2:prev = &a1 112 | a1 113 | 114 | b = [4 5] => 115 | b2 = { 2, nil, nil } 116 | b1 = { 1, b2 XOR nil } 117 | b2:ptrdiff = nil XOR b1 118 | b1 119 | 120 | c = cat (tail a) b => 121 | a_end = tail a => ... # find last item in list a 122 | a2 = copy a_end 123 | b2 = copy b 124 | a_tail:ptrdiff = 125 | 126 | 127 | c = cat a b => List{ 0, a XOR b } 128 | d = [6 7] => List{ 2, 6, 7 } 129 | e = cat c d => List{ 0, c XOR d } 130 | 131 | # ------------ 132 | # Lists are always constant (but values themselves may be mutable) and has a diffptr. 133 | # See: http://www.linuxjournal.com/article/6828 "A Memory-Efficient Doubly Linked List" 134 | 135 | List { 136 | T value 137 | List* ptrdiff 138 | } 139 | a = [1 2 3] => 140 | a3 = { 3, nil } 141 | a2 = { 2, nil } 142 | a1 = { 1, a2 XOR nil } 143 | a2:ptrdiff = a3 XOR a1 144 | a3:ptrdiff = nil XOR a2 145 | a1 146 | 147 | b = [4 5] => 148 | b2 = { 2, nil } 149 | b1 = { 1, b2 XOR nil } 150 | b2:ptrdiff = nil XOR b1 151 | b1 152 | 153 | c = cat (tail a) b => 154 | a_end = tail a => ... # find last item in list a 155 | a2 = copy a_end 156 | b2 = copy b 157 | a_tail:ptrdiff = 158 | 159 | 160 | c = cat a b => List{ 0, a XOR b } 161 | d = [6 7] => List{ 2, 6, 7 } 162 | e = cat c d => List{ 0, c XOR d } 163 | # e.. 164 | # c.. 165 | # a [1 2 3] 166 | # b [4 5] 167 | # d [6 7] 168 | # 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /examples/program2-multi-line-func-body.hue: -------------------------------------------------------------------------------- 1 | # Next up: Allow more than one expression in a function body 2 | #A = ^(x Int) Int -> 12 3 | G = ^(x Int) Int: 4 | y = x * 9 \ # ... Do not stop at the next NewLine 5 | + 5 # expr: y = x * 9 + 5 6 | y / 4 - (92 > 91) # return: expr: y / 4 - 92 7 | 8 | H = G 1 * (F 2 3 4) 5 # C equiv: H = G(1 * F(2,3,4), 5) 9 | 10 | # Todo: Control flow: for 11 | # Todo: Control flow: while 12 | -------------------------------------------------------------------------------- /examples/program3-eq.hue: -------------------------------------------------------------------------------- 1 | # Next up: Allow more than one expression in a function body 2 | a = 5 3 | F = ^(a Int) Int: a / 3 4 | x = 4 == 5 # x should be folded to 0 Int 5 | y = F x # Here, x is a i1 and will be expanded to an i64 6 | -------------------------------------------------------------------------------- /examples/program4-func-params.hue: -------------------------------------------------------------------------------- 1 | # a, b and c has the type Int. d has the type Float 2 | F = ^(a, b, c Int, d Float) Int: x = 45 / 6 3 | a / b * c * x 4 | y = F 1 2 3 4.5 5 | -------------------------------------------------------------------------------- /examples/program5-bool.hue: -------------------------------------------------------------------------------- 1 | # Boolean values and type 2 | a = true 3 | b Bool = false 4 | boolsAreEq = ^(a, b Bool) Bool: a == b 5 | e = boolsAreEq a b 6 | -------------------------------------------------------------------------------- /examples/program6-putchar.hue: -------------------------------------------------------------------------------- 1 | # Writes "Hello World\n" to stdout 2 | p = extern putchar (ch Int) Int 3 | H = 72 4 | e = 101 5 | l = 108 6 | o = 111 7 | _ = 32 8 | W = 87 9 | r = 114 10 | d = 100 11 | LF = 10 12 | p H 13 | p e 14 | p l 15 | p l 16 | p o 17 | p _ 18 | p W 19 | p o 20 | p r 21 | p l 22 | p d 23 | p LF 24 | -------------------------------------------------------------------------------- /examples/program7-fib.hue: -------------------------------------------------------------------------------- 1 | # -- WIP -- (symbol reachability of "fib") 2 | fib = ^(N Int) Int: 3 | if N < 2: 4 | N 5 | else: 6 | (fib n-1) + fib n-2 7 | 8 | func fib Int (N Int) if N < 2 N else (fib n-1) + (fib n-2) 9 | fib = ^ Int (N Int) if N < 2 N else (fib n-1) + (fib n-2) 10 | 11 | fib = ^ Int (N Int) 12 | if N < 2 N else (fib n-1) + (fib n-2) 13 | 14 | fib = n Int -> if n < 2 n else (fib n-1) + (fib n-2) 15 | 16 | FOO = map "foo" ^ Char (c Char) Character:toUpper c 17 | FOO = map "foo" ^ Char (c Char) -> Character:toUpper c 18 | 19 | Character = { toUpper = func Char (c Char) c + 26 } 20 | typeof Character # -> {toUpper = func Char (c Char)} 21 | 22 | 23 | age = years_since 1983 5 17 24 | unless = macro test a b -> if test b else a 25 | 26 | fib = func n Int -> unless n < 2 (fib n - 1) + (fib n - 2) n 27 | 28 | foo = func a, b, c Int, d Float -> a * b * c * d 29 | 30 | println = func (a Int) 31 | hue:io:println_int a 32 | 33 | FOO = map "foo" (c Char) -> Character:toUpper c 34 | 35 | # FuncExpr = 'func' FuncType Expression+ 36 | # FuncTypeExpr = 'funct' FuncType 37 | # 38 | # FuncType = Result? '(' Parameters? ')' 39 | # Result = TypeList 40 | # Parameters = VariableList 41 | # 42 | 43 | # MacroExpr = 'macro' SymbolList '->' Expression 44 | # SymbolList = Identifier+ 45 | 46 | # Some macro wizardry to add type aliasing: 47 | type = macro T -> macro -> T 48 | Text = type [Char] # == Text = macro -> [Char] 49 | # Now we can write 50 | toUpper2 = (s Text) -> map s (func c -> Character:toUpper c) 51 | # instead of 52 | toUpper = ^(s) map s func (c) Character:toUpper c 53 | 54 | # Instead of allowing multiple return values, a function can instead return either a record... 55 | userInfo = ^(id) {id = 123, name = "John", age = 29} 56 | nameForID = ^(id) (userInfo id):name 57 | # ...or list 58 | userInfo = func (id Int) ["John", "123", "29"] 59 | nameForID = func (id Int) (userInfo id):0 60 | 61 | 62 | # Templates? We probably need something along these lines to allow 63 | # Calling functions operating on "base types", e.g. map which operates 64 | # on list: 65 | map = func (list [?1], modifier func(?1)?1) [?1] 66 | with item in list modifier item 67 | # This means that map's implementations are lazy and compile-time dynamic. As soon as we 68 | # hit a use of map, we lazily implement the function: 69 | x = map "abc" Character:toUpper # ?1 = Char -- ?1 is defined by the first substitution ("Char") 70 | # The above would case this implicit function to be created: 71 | map = func (list [Char], modifier func(Char)Char) [Char] 72 | with item in list modifier item 73 | # In a sense, the template is a macro which is expanded at first use to define the function 74 | # being implemented. 75 | 76 | # Or we could just rely on macros: 77 | mapimpl = macro T -> func (list [T], modifier func(T)T) [T] 78 | with item in list modifier item 79 | map = mapimpl Char 80 | map = mapimpl Int 81 | # Yeah, macros are powerful and by not having a special template construct, the language 82 | # stays simple. 83 | 84 | 85 | # What if all functions are lazily implemented, based on input type? 86 | foo = func a b c -> a * b * c 87 | # Means "foo represents a funtion that takes 3 arguments" and the body is not evaluated 88 | # until an implementation is created. 89 | bar = foo 1 2 3 90 | # Would: 91 | # 1. Convert arguments to a list of types 92 | # 2. Look for an implementation of foo that takes the same type of arguments 93 | # 3. If not found: 94 | # 3.1. create an implementation of foo that takes the arguments 95 | foo = funcimpl ? (a Int b Int c Int) a * b * c 96 | # 3.2. infer type by looking at the type returned by the last expression 97 | # 3.3. finalize implementation 98 | foo = funcimpl Int (a Int b Int c Int) a * b * c 99 | 100 | # If we want to export a function, we have two very different ways of doing so: 101 | # 1. Export each variant explicitly: 102 | export foo Int (Int Int Int) 103 | export foo Float (Float Float Int) 104 | ... 105 | # 2. Decide to always make Hue source code available, thus we can export an lazy 106 | # definition and have any importers compile that abstract function into implementations. 107 | export foo 108 | # In some other module: 109 | use foomodule 110 | bar = foo 1 2 3 111 | 112 | # 2.2: 113 | # A module exporting foo could in fact mark any implementations it produced as "public" 114 | # and export metadata about these implementations. That way another module could simply 115 | # use those implementations. 116 | # When generating an implementation, that impl should be namespaced according to the origin 117 | # of the abstract definition and not for whatever module caused the implementation. 118 | # 119 | # E.g. 120 | module Foo/1.0.0 121 | export foo = func a b c -> a * b * c 122 | export bar = foo 1 2 3 123 | # Foo would be exported with the following metadata: 124 | # 125 | # env->getModule("foo")->metadata => { 126 | # symbols: { 127 | # foo: { 128 | # type: Func, 129 | # variants: [ {args: ["a","b","c"], body: "a * b * c"} ], 130 | # }, 131 | # bar: { type: Int, value: 6 }, 132 | # }, 133 | # } 134 | # 135 | # The system environment would manage all implementations: 136 | # 137 | # env->invariants() => { "Foo:foo": [ "III$I" ] } 138 | # 139 | # Where each invariant would be guaranteed to exist as e.g: 140 | # 141 | # public i64 Foo$foo$III$I i64, i64, i64 ... 142 | # 143 | # Another module using Foo: 144 | module other 145 | import Foo 146 | bar = Foo:foo 1.0 2.0 3.0 147 | # Would cause an implementation to be created unless one already exists. 148 | # 149 | # env->invariants() => { "Foo:foo": [ "III$I", "FFF$F" ] } 150 | # 151 | # 152 | # Actually, that is crazy since we would have to generate this code at runtime, which would break 153 | # the awesomeness of strong typing. It's probably better if the compiler generates effectively 154 | # redundant but isolated implementations. 155 | # 156 | # E.g. when compiling the other module, the compiler would 157 | # 158 | 159 | # (defn fib (N Int) 160 | # (if (N < 2) 161 | # N 162 | # (+ (fib (- n 1)) (fib (- n 2))))) 163 | 164 | #x = ? (N < 10): 165 | # a = 5 166 | # a * 5 167 | # (N < 20): 2 168 | # (N < 30): 3 169 | # :N 170 | # 171 | #x = ? (N < 10): 5 * 5; (N < 20): 2; (N < 30): 3; : N 172 | 173 | # x = if (N < 10): 5 * 5; if (N < 20): 2; if (N < 30): 3; else: N 174 | # 175 | # x = ^(N Int) Int: 176 | # if (N < 10): 5 * 5 177 | # if (N < 20): 2 178 | # else: 4 179 | # if (N < 30): 3 180 | # else: N 181 | 182 | # IfExpression = TestExpr+ BlockExpression 183 | # TestExpr = '?' Expression ':' BlockExpression 184 | # 185 | # Examples (=> solutions): 186 | # 187 | # ? (N < 1): 1; (N < 10): 2; N => N(IntMin..0) == 1 188 | # => N(1..9) == 2 189 | # => N(10..) == N 190 | # 191 | # ? (N < 1): 1; 3 => N(IntMin..0) == 1 192 | # => N(1..) == 3 193 | # 194 | 195 | 196 | #x = ? (N < 10): 1 197 | # (N < 20): 2 198 | # N 199 | 200 | #x = ? (N < 10): 1; N 201 | # 202 | #bestN = ^(N Int) Int: 203 | # if (N < 10): 204 | # x = 56 205 | # fooBar x N 206 | # (N < 20): 207 | # x = 56 208 | # fooBar x N 209 | # (N < 30): 210 | # x = 56 211 | # fooBar x N 212 | # (N < 40): 2 213 | # : N 214 | # 215 | #bestN = ^(N Int) Int: 216 | # ? (N < 10): 217 | # f = fooBar x N 218 | # ? (f == 5): f * 76 219 | # : f 220 | # ? (N < xofr 6): 221 | # 2 222 | # ?: N 223 | # 224 | # 225 | #fib = ^(N Int) Int: 226 | # x = ? (N < 2) N 227 | # (fib n-1) + fib n-2 228 | # x * 7 229 | # 230 | #bestN = ^(N Int) Int -> 231 | # ? (N < 10) fooBar x N 232 | # (N < 20) 2 233 | # N 234 | # 235 | #bestN = ^(N Int) Int -> ? (N < 10) fooBar x N; (N < 20) 2; N 236 | # 237 | #x = ^(x Float) -> x = 65 238 | # 239 | #x = ? (N < 10) 1 : 3 240 | 241 | # Recursive fibonacci 242 | #fib = ^(N Int) Int -> ?(N < 2) N : (fib n-1) + fib n-2 243 | 244 | -------------------------------------------------------------------------------- /examples/program8-if-then-else.hue: -------------------------------------------------------------------------------- 1 | #foo = extern foo (_ Int) Int 2 | #x = foo 0 3 | 4 | #c = if x < 1: foo 100; if x < 2: foo 200; else: foo 300 5 | # PASS 6 | 7 | #c = if x < 1: 8 | # foo 100 9 | # if x < 2: 10 | # foo 200 11 | # else: 12 | # 300 13 | ## PASS 14 | 15 | #c = if x < 1: 16 | # Y = foo 100 17 | # if x < 2: 18 | # foo Y 19 | # else: 20 | # 300 21 | # else: 22 | # 400 23 | # PASS 24 | 25 | foobarbaz = ^(x, y Int) Int: z = x * y * 9 26 | z / 4 27 | 28 | foobarbaz2 = if 5 < 1: 29 | ^(x, y Int) Int: 30 | foobarbaz x * y * 2 5 31 | else: 32 | ^(x, y Int) Int: 33 | x * y * 3 34 | 35 | #a = foo if x < 1: 100; else: 300 36 | 37 | #putc = extern putchar (ch Int) Int 38 | # 39 | #A = 65 40 | #B = 66 41 | #C = 67 42 | # 43 | #N = 1 44 | #char = if N > 2: A; if N > 1: B; C 45 | # 46 | #putc char 47 | #putc 10 48 | -------------------------------------------------------------------------------- /examples/program9-number-literals.hue: -------------------------------------------------------------------------------- 1 | f1 = 1.2 2 | f2 = .2 3 | f3 = 125E+1.2.3 4 | f4 = 0.2_51 5 | åland = 4.25E+90 6 | f5 = 0.6e-4 7 | i = 123 8 | ネ = 01_23 9 | x1 = 0x01fa3 10 | x2 = 0x5_3_9 11 | 12 | foo = extern foo (a,b,c,d,e,f Float, g,h,i,j Int) Int 13 | y = foo f1 f2 f3 f4 åland f5 i ネ x1 x2 14 | -------------------------------------------------------------------------------- /examples/tokenize.cc: -------------------------------------------------------------------------------- 1 | // Tokenizes a program -- essentially reading lexical components. 2 | // 3 | // clang++ -std=c++11 -o build/example-tokenize examples/tokenize.cc \ 4 | // -Ibuild/include -Lbuild/lib -lhuert && build/example-tokenize 5 | // 6 | #include "../src/parse/Tokenizer.h" 7 | #include "../src/parse/TokenBuffer.h" 8 | #include "../src/parse/FileInput.h" 9 | 10 | #include 11 | 12 | using namespace hue; 13 | 14 | int main(int argc, char **argv) { 15 | // Read input file 16 | Text textSource; 17 | const char* filename = argc > 1 ? argv[1] : "examples/program1.hue"; 18 | if (!textSource.setFromUTF8FileContents(filename)) { 19 | std::cerr << "Failed to read file '" << filename << "'" << std::endl; 20 | return 1; 21 | } 22 | 23 | // A tokenizer produce tokens parsed from a ByteInput 24 | Tokenizer tokenizer(textSource); 25 | 26 | // A TokenBuffer reads tokens from a Tokenizer and maintains limited history 27 | TokenBuffer tokens(tokenizer); 28 | 29 | while (1) { 30 | const Token &token = tokens.next(); 31 | 32 | if (token.type == Token::Unexpected) { 33 | std::cout << "Error: Unexpected token '" << token.textValue 34 | << "' at " << token.line << ':' << token.column << std::endl; 35 | break; 36 | } 37 | 38 | std::cout << "\e[34;1m>> " << token.toString() << "\e[0m"; 39 | 40 | // list all available historical tokens 41 | // size_t n = 1; 42 | // while (n < tokens.count()) { 43 | // std::cout << "\n " << tokens[n++].toString() << ")"; 44 | // } 45 | std::cout << std::endl; 46 | 47 | // An End token indicates the end of the token stream and we must 48 | // stop reading the stream. 49 | if (token.type == Token::End || token.type == Token::Error) break; 50 | } 51 | 52 | return 0; 53 | } -------------------------------------------------------------------------------- /src/DebugTrace.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | #ifndef HUE__DEBUG_TRACE_H 5 | #define HUE__DEBUG_TRACE_H 6 | 7 | #include 8 | 9 | static volatile int g_DebugTrace_depth = 0; 10 | 11 | namespace hue { 12 | 13 | class DebugTrace { 14 | const char *primary_; 15 | const char *secondary_; 16 | int line_; 17 | public: 18 | DebugTrace(const char *primary, const char *secondary, int line = 0) 19 | : primary_(primary), secondary_(secondary), line_(line) { 20 | fprintf(stderr, "%*s\e[33;1m-> %d %s \e[30;1m%s:%d\e[0m\n", g_DebugTrace_depth*2, "", 21 | g_DebugTrace_depth, primary_, secondary_, line_); 22 | ++g_DebugTrace_depth; 23 | } 24 | ~DebugTrace() { 25 | --g_DebugTrace_depth; 26 | fprintf(stderr, "%*s\e[33m<- %d %s \e[30;1m%s:%d\e[0m\n", g_DebugTrace_depth*2, "", 27 | g_DebugTrace_depth, primary_, secondary_, line_); 28 | } 29 | }; 30 | 31 | 32 | #ifndef DEBUG_TRACE 33 | #define DEBUG_TRACE hue::DebugTrace _DebugTrace_##__LINE__(__FUNCTION__, __FILE__, __LINE__) 34 | #endif 35 | 36 | } // namespace hue 37 | #endif // HUE__DEBUG_TRACE_H 38 | -------------------------------------------------------------------------------- /src/Logger.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | #include "Logger.h" 5 | 6 | using namespace hue; 7 | 8 | Logger::Level Logger::currentLevel = Logger::Debug; 9 | volatile uint8_t Logger::isATTY = 0; 10 | -------------------------------------------------------------------------------- /src/Logger.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | #ifndef HUE__LOGGER_H 5 | #define HUE__LOGGER_H 6 | 7 | // Use these macros in your code (Don't use hue::Logger::begin etc). 8 | // 9 | // Example: 10 | // 11 | // // Debug message 12 | // rlog("Response code: " << rsp.code << " (" << rsp.toString()); 13 | // 14 | // // Warning message 15 | // rlogw("Failed to chmod(\"" << filename << "\", " << mode << ")"); 16 | // 17 | // // With explicit level 18 | // rlogl(hue::Logger::Warning, "Failed to chmod(\"" << filename << "\", " 19 | // << mode << ")"); 20 | // 21 | #if NDEBUG 22 | // Strip trace and debug messages from non-debug builds 23 | #define rtrace() do{}while(0) 24 | #define rlog(...) do{}while(0) 25 | #else 26 | #define rtrace() rlogl(hue::Logger::Trace, "") 27 | #define rlog(args) rlogl(hue::Logger::Debug, args) 28 | #endif 29 | #define rlogw(args) rlogl(hue::Logger::Warning, args) 30 | #define rloge(args) rlogl(hue::Logger::Error, args) 31 | 32 | #define rlogl(level, A) do { if (level >= hue::Logger::currentLevel) { \ 33 | hue::Logger::end(hue::Logger::begin(level) << A, __FILE__, __LINE__); } } while(0) 34 | 35 | // ---------------------------------------------------------------------------- 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | namespace hue { 42 | 43 | class Logger { 44 | public: 45 | enum Level { 46 | Trace = 0, 47 | Debug, 48 | Warning, 49 | Error, 50 | }; 51 | static Level currentLevel; 52 | static volatile uint8_t isATTY; 53 | static std::ostream& begin(const Logger::Level level) { 54 | if (Logger::isATTY == 0) Logger::isATTY = isatty(1) ? 1 : 2; 55 | std::ostream& s = std::clog; 56 | if (Logger::isATTY) { 57 | s << (level == Trace ? "\e[30;47m " 58 | : level == Debug ? "\e[30;44m " 59 | : level == Warning ? "\e[30;43m " 60 | : "\e[30;41m "); 61 | } 62 | return s << (level == Trace ? 'T' 63 | : level == Debug ? 'D' 64 | : level == Warning ? 'W' 65 | : 'E') << (Logger::isATTY ? " \e[0m " : " "); 66 | } 67 | static std::ostream& end(std::ostream& s, const char *filename, const int lineno) { 68 | s << (Logger::isATTY ? " \e[30;1;40m[" : " [") 69 | << filename << ':' << lineno 70 | << (Logger::isATTY ? "]\e[0m" : "]"); 71 | return s << std::endl;// << std::flush; 72 | } 73 | private: 74 | explicit Logger() {} 75 | }; 76 | 77 | } // namespace hue 78 | #endif // HUE__LOGGER_H 79 | -------------------------------------------------------------------------------- /src/Mangle.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "Mangle.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace hue { 10 | 11 | // MangledTypeList = MangledType* 12 | std::string mangle(const ast::TypeList& types) { 13 | std::ostringstream ss; 14 | ast::TypeList::const_iterator it = types.begin(); 15 | for (; it != types.end(); ++it) { 16 | const ast::Type* T = *it; 17 | ss << mangle(*T); 18 | } 19 | return ss.str(); 20 | } 21 | 22 | // MangledVarList = MangledTypeList 23 | std::string mangle(const ast::VariableList& vars) { 24 | std::ostringstream ss; 25 | ast::VariableList::const_iterator it = vars.begin(); 26 | for (; it != vars.end(); ++it) { 27 | assert((*it)->type() != 0); 28 | ss << mangle(*(*it)->type()); 29 | } 30 | return ss.str(); 31 | } 32 | 33 | // MangledFuncType = '$' MangledVarList '$' MangledTypeList 34 | // 35 | // (a Int) Int -> $I$I 36 | // 37 | std::string mangle(const ast::FunctionType& funcType) { 38 | std::string mname = "$"; 39 | ast::VariableList* args = funcType.args(); 40 | if (args) mname += mangle(*args); 41 | mname += '$'; 42 | const ast::Type* returnType = funcType.resultType(); 43 | if (returnType) mname += mangle(*returnType); 44 | return mname; 45 | } 46 | 47 | /* 48 | Itanium C++ ABI name mangling rules: 49 | 50 | 51 | ::= v # void 52 | ::= w # wchar_t 53 | ::= b # bool 54 | ::= c # char 55 | ::= a # signed char 56 | ::= h # unsigned char 57 | ::= s # short 58 | ::= t # unsigned short 59 | ::= i # int 60 | ::= j # unsigned int 61 | ::= l # long 62 | ::= m # unsigned long 63 | ::= x # long long, __int64 64 | ::= y # unsigned long long, __int64 65 | ::= n # __int128 66 | ::= o # unsigned __int128 67 | ::= f # float 68 | ::= d # double 69 | ::= e # long double, __float80 70 | ::= g # __float128 71 | ::= z # ellipsis 72 | ::= Dd # IEEE 754r decimal floating point (64 bits) 73 | ::= De # IEEE 754r decimal floating point (128 bits) 74 | ::= Df # IEEE 754r decimal floating point (32 bits) 75 | ::= Dh # IEEE 754r half-precision floating point (16 bits) 76 | ::= Di # char32_t 77 | ::= Ds # char16_t 78 | ::= Da # auto (in dependent new-expressions) 79 | ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) 80 | ::= u # vendor extended type 81 | */ 82 | 83 | // MangledType = 84 | std::string mangle(const ast::Type& T) { 85 | if (T.typeID() == ast::Type::Named) { 86 | std::string utf8name = T.name().UTF8String(); 87 | char buf[12]; 88 | int len = snprintf(buf, 12, "N%zu", utf8name.length()); 89 | utf8name.insert(0, buf, len); 90 | return utf8name; 91 | } else switch (T.typeID()) { 92 | case ast::Type::Float: return "d"; 93 | case ast::Type::Int: return "x"; 94 | case ast::Type::Char: return "j"; 95 | case ast::Type::Byte: return "a"; 96 | case ast::Type::Bool: return "b"; 97 | case ast::Type::FuncT: return "F"; // TODO 98 | case ast::Type::StructureT: 99 | return mangle(static_cast(T)); 100 | default: return ""; 101 | } 102 | } 103 | 104 | std::string mangle(const ast::StructType& ST) { 105 | std::string cname; 106 | size_t count = ST.size(); 107 | 108 | char buf[12]; 109 | int len = snprintf(buf, 12, "S%zu", count); 110 | cname.insert(0, buf, len); 111 | 112 | for (size_t i = 0; i < count; ++i ) { 113 | cname += mangle(*ST.types()[i]); 114 | } 115 | return cname; 116 | } 117 | 118 | ast::Type demangle(const std::string& mangleID) { 119 | switch (mangleID[0]) { 120 | case 'd': return ast::Type(ast::Type::Float); 121 | case 'x': return ast::Type(ast::Type::Int); 122 | case 'j': return ast::Type(ast::Type::Char); 123 | case 'a': return ast::Type(ast::Type::Byte); 124 | case 'b': return ast::Type(ast::Type::Bool); 125 | case 'F': return ast::Type(ast::Type::FuncT); 126 | case 'N': { 127 | return ast::Type(Text(mangleID.substr(1))); 128 | } 129 | default: return ast::Type(ast::Type::Unknown); 130 | } 131 | } 132 | 133 | std::string mangle(llvm::Type* T) { 134 | switch(T->getTypeID()) { 135 | case llvm::Type::VoidTyID: return "v"; ///< 0: type with no size 136 | case llvm::Type::FloatTyID: return "f"; ///< 1: 32-bit floating point type 137 | case llvm::Type::DoubleTyID: return "d"; ///< 2: 64-bit floating point type 138 | case llvm::Type::X86_FP80TyID: return "e"; ///< 3: 80-bit floating point type (X87) 139 | case llvm::Type::FP128TyID: return "g"; ///< 4: 128-bit floating point type (112-bit mantissa) 140 | case llvm::Type::PPC_FP128TyID: return "De"; ///< 5: 128-bit floating point type (two 64-bits, PowerPC) 141 | //case llvm::Type::LabelTyID: return ///< 6: Labels 142 | //case llvm::Type::MetadataTyID: return ///< 7: Metadata 143 | //case llvm::Type::X86_MMXTyID: return ///< 8: MMX vectors (64 bits, X86 specific) 144 | 145 | // Derived types... see DerivedTypes.h file. 146 | // Make sure FirstDerivedTyID stays up to date! 147 | case llvm::Type::IntegerTyID: { 148 | switch (T->getPrimitiveSizeInBits()) { 149 | case 8: return "a"; 150 | case 16: return "t"; 151 | case 32: return "j"; 152 | case 64: return "x"; 153 | default: return "?"; 154 | } 155 | } 156 | case llvm::Type::FunctionTyID: 157 | return std::string("F") + mangle(static_cast(T)); ///< 10: Functions 158 | 159 | // case StructTyID: return ///< 11: Structures 160 | // case ArrayTyID: return ///< 12: Arrays 161 | // case PointerTyID: return ///< 13: Pointers 162 | // case VectorTyID: return ///< 14: SIMD 'packed' format, or other vector type 163 | default: return "?"; 164 | } 165 | } 166 | 167 | 168 | std::string mangle(llvm::FunctionType* FT) { 169 | std::string mname = "$"; 170 | for (llvm::FunctionType::param_iterator I = FT->param_begin(), 171 | E = FT->param_end(); 172 | I != E; ++I) 173 | { 174 | mname += mangle(*I); 175 | } 176 | mname += '$'; 177 | mname += mangle(FT->getReturnType()); 178 | return mname; 179 | } 180 | 181 | 182 | } // namespace hue 183 | -------------------------------------------------------------------------------- /src/Mangle.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #ifndef _HUE_CODEGEN_MANGLE_INCLUDED 4 | #define _HUE_CODEGEN_MANGLE_INCLUDED 5 | 6 | #include "ast/Type.h" 7 | #include "ast/StructType.h" 8 | #include "ast/Function.h" 9 | 10 | #include 11 | #include 12 | 13 | namespace hue { 14 | 15 | std::string mangle(const ast::TypeList& types); 16 | std::string mangle(const ast::VariableList& vars); 17 | std::string mangle(const ast::FunctionType& funcType); 18 | std::string mangle(const ast::StructType& structType); 19 | std::string mangle(const ast::Type& T); 20 | std::string mangle(llvm::Type* T); 21 | std::string mangle(llvm::FunctionType* FT); 22 | 23 | ast::Type demangle(const std::string& mangleID); 24 | 25 | } // namespace hue 26 | #endif // _HUE_CODEGEN_MANGLE_INCLUDED 27 | -------------------------------------------------------------------------------- /src/Text.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #include "Text.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace hue { 12 | 13 | 14 | // Text(const UChar* text, size_t size, bool copy) : std::basic_string() { 15 | // reserve(size); 16 | // UChar* data = const_cast(data()); 17 | // 18 | // } 19 | 20 | const Text Text::Empty; 21 | 22 | 23 | Text& Text::appendUTF8String(const std::string& utf8string) throw(utf8::invalid_code_point) { 24 | utf8::utf8to32(utf8string.begin(), utf8string.end(), std::back_inserter(*this)); 25 | return *this; 26 | } 27 | 28 | 29 | bool Text::setFromUTF8String(const std::string& utf8string) { 30 | clear(); 31 | bool ok = true; 32 | try { 33 | utf8::utf8to32(utf8string.begin(), utf8string.end(), std::back_inserter(*this)); 34 | } catch (const utf8::invalid_code_point &e) { 35 | clear(); 36 | ok = false; 37 | } 38 | return ok; 39 | } 40 | 41 | 42 | bool Text::setFromUTF8Data(const uint8_t* data, const size_t length) { 43 | return setFromUTF8String(std::string(reinterpret_cast(data), length)); 44 | } 45 | 46 | 47 | bool Text::setFromUTF8InputStream(std::istream& is, size_t length) { 48 | if (!is.good()) return false; 49 | 50 | char *buf = NULL; 51 | std::string utf8string; 52 | 53 | if (length != 0) { 54 | buf = new char[length]; 55 | is.read(buf, length); 56 | utf8string.assign(buf, length); 57 | } else { 58 | length = 4096; 59 | buf = new char[length]; 60 | while (is.good()) { 61 | is.read(buf, length); 62 | utf8string.append(buf, is.gcount()); 63 | } 64 | } 65 | 66 | return setFromUTF8String(utf8string); 67 | } 68 | 69 | 70 | //bool Text::setFromUTF8FileContents(const char* filename) { 71 | // std::ifstream ifs(filename, std::ifstream::in | std::ifstream::binary); 72 | // if (!ifs.good()) return false; 73 | // 74 | // ifs.seekg(0, std::ios::end); 75 | // size_t length = ifs.tellg(); 76 | // ifs.seekg(0, std::ios::beg); 77 | // 78 | // bool ok = setFromUTF8InputStream(ifs, length); 79 | // ifs.close(); 80 | // return ok; 81 | //} 82 | 83 | 84 | bool Text::setFromUTF8FileOrSTDIN(const char* filename, std::string& error) { 85 | using namespace llvm; 86 | OwningPtr File; 87 | if (error_code ec = MemoryBuffer::getFileOrSTDIN(filename, File)) { 88 | error.assign(ec.message()); 89 | return false; 90 | } 91 | if (!setFromUTF8Data((const uint8_t*)File->getBufferStart(), File->getBufferSize())) { 92 | error.assign("Input is not valid UTF-8 text"); 93 | return false; 94 | } 95 | return true; 96 | } 97 | 98 | 99 | std::string Text::UTF8String() const { 100 | std::string utf8string; 101 | try { 102 | utf8::utf32to8(this->begin(), this->end(), std::back_inserter(utf8string)); 103 | } catch (const utf8::invalid_code_point &e) { 104 | utf8string.clear(); 105 | } 106 | return utf8string; 107 | } 108 | 109 | 110 | ByteList Text::rawByteList() const { 111 | Text::const_iterator it = begin(); 112 | ByteList bytes; 113 | 114 | for (; it != end(); ++ it) { 115 | UChar c = *it; 116 | if (c < 0x100) { 117 | bytes.push_back(static_cast(c)); 118 | } else if (c < 0x10000) { 119 | bytes.push_back(static_cast(c >> 8)); 120 | bytes.push_back(static_cast(c & 0xff)); 121 | } else if (c < 0x1000000) { 122 | bytes.push_back(static_cast(c >> 16)); 123 | bytes.push_back(static_cast(c >> 8 & 0xff)); 124 | bytes.push_back(static_cast(c & 0xff)); 125 | } else if (c < 0x1000000) { 126 | bytes.push_back(static_cast(c >> 24)); 127 | bytes.push_back(static_cast(c >> 16 & 0xff)); 128 | bytes.push_back(static_cast(c >> 8 & 0xff)); 129 | bytes.push_back(static_cast(c & 0xff)); 130 | } 131 | } 132 | 133 | return bytes; 134 | } 135 | 136 | 137 | ByteString Text::rawByteString() const { 138 | Text::const_iterator it = begin(); 139 | ByteString bytes; 140 | 141 | for (; it != end(); ++ it) { 142 | UChar c = *it; 143 | if (c < 0x100) { 144 | bytes.append(1, static_cast(c)); 145 | } else if (c < 0x10000) { 146 | bytes.append(1, static_cast(c >> 8)); 147 | bytes.append(1, static_cast(c & 0xff)); 148 | } else if (c < 0x1000000) { 149 | bytes.append(1, static_cast(c >> 16)); 150 | bytes.append(1, static_cast(c >> 8 & 0xff)); 151 | bytes.append(1, static_cast(c & 0xff)); 152 | } else if (c < 0x1000000) { 153 | bytes.append(1, static_cast(c >> 24)); 154 | bytes.append(1, static_cast(c >> 16 & 0xff)); 155 | bytes.append(1, static_cast(c >> 8 & 0xff)); 156 | bytes.append(1, static_cast(c & 0xff)); 157 | } 158 | } 159 | 160 | return bytes; 161 | } 162 | 163 | 164 | // static 165 | std::string Text::UCharToUTF8String(const UChar c) { 166 | std::string utf8string; 167 | try { 168 | utf8::append(c, std::back_inserter(utf8string)); 169 | } catch (const utf8::invalid_code_point &e) { 170 | utf8string.clear(); 171 | } 172 | return utf8string; 173 | } 174 | 175 | 176 | std::vector Text::split(UChar separator) const { 177 | std::vector components; 178 | Text buf; 179 | 180 | // TODO: Optimize by avoiding copying of buf 181 | 182 | for (Text::const_iterator I = begin(), E = end(); I != E; ++I) { 183 | if (*I == separator) { 184 | if (!buf.empty()) { 185 | components.push_back(buf); 186 | buf.clear(); 187 | } 188 | } else { 189 | buf.push_back(*I); 190 | } 191 | } 192 | 193 | if (!buf.empty()) { 194 | components.push_back(buf); 195 | } 196 | 197 | return components; 198 | } 199 | 200 | 201 | Text Text::join(const std::vector& components) const { 202 | if (components.size() == 0) return Text(); 203 | else if (components.size() == 1) return components[0]; 204 | 205 | Text text(components[0]); 206 | 207 | std::vector::const_iterator I = components.begin(), E = components.end(); 208 | ++I; // components[0] 209 | for (;I != E; ++I) { 210 | text += *this; 211 | text += *I; 212 | } 213 | 214 | return text; 215 | } 216 | 217 | 218 | const UChar NullChar = 0; 219 | 220 | } // namespace hue 221 | -------------------------------------------------------------------------------- /src/Text.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #ifndef _HUE_TEXT_INCLUDED 4 | #define _HUE_TEXT_INCLUDED 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace hue { 14 | 15 | // Represents a Unicode character (or "codepoint" if you will) 16 | typedef uint32_t UChar; 17 | 18 | // Represents a sequence of bytes. 19 | typedef std::vector ByteList; 20 | typedef std::basic_string ByteString; 21 | 22 | // Represents Unicode text. 23 | class Text : public std::basic_string { 24 | public: 25 | typedef std::vector List; 26 | typedef std::vector ConstList; 27 | 28 | static const Text Empty; 29 | 30 | Text() : std::basic_string() {} 31 | Text(const char* utf8data) : std::basic_string() { 32 | setFromUTF8String(utf8data); 33 | } 34 | Text(const std::string& utf8string) : std::basic_string() { 35 | setFromUTF8String(utf8string); 36 | } 37 | // Text(const Text& other) : std::basic_string(other) { 38 | // setFromUTF8String(utf8string); 39 | // } 40 | //Text(const UChar* text, size_t size, bool copy = true); 41 | 42 | // Replace the contents of the receiver by reading the istream, which is expected to 43 | // produce UTF-8 data. 44 | // Returns false if the stream could not be read or the contents is not UTF-8 text. 45 | bool setFromUTF8InputStream(std::istream& ifs, size_t length = 0); 46 | 47 | // Replace the contents of the receiver with the contents of the file pointed to by 48 | // *filename*. The contents of the file is expected to be encoded as UTF-8. 49 | // If *filename* is "-", then data is read from STDIN. 50 | // Returns false if the file could not be read or the contents is not UTF-8 text. 51 | bool setFromUTF8FileOrSTDIN(const char* filename, std::string& error); 52 | 53 | // Replace the contents of the receiver by decoding UTF-8 data. 54 | bool setFromUTF8String(const std::string& data); 55 | inline bool setFromUTF8String(const char* utf8data) { return setFromUTF8String(std::string(utf8data)); } 56 | bool setFromUTF8Data(const uint8_t* data, const size_t length); 57 | 58 | // Append UTF-8 data to the end of the receiver. Returns *this. 59 | Text& appendUTF8String(const std::string& utf8string) throw(utf8::invalid_code_point); 60 | 61 | // Create a UTF-8 representation of the text. Returns an empty string if encoding failed. 62 | std::string UTF8String() const; 63 | inline std::string toString() const { return UTF8String(); } // alias 64 | 65 | // Create a sequence of bytes by interpreting each character in the text as 1-4 bytes. 66 | // E.g. A 3-octet-wide unicode character U+1F44D is represented as the bytes 0x1, 0xF4 and 0x4D. 67 | ByteList rawByteList() const; 68 | ByteString rawByteString() const; 69 | 70 | // Create a list of components in the receiver separated by *separator* 71 | std::vector split(UChar separator) const; 72 | 73 | // Create text where *components* are joined by instances of the receiver. 74 | Text join(const std::vector& components) const; 75 | 76 | // Assignment operators 77 | inline Text& operator= (const char* rhs) { 78 | setFromUTF8String(rhs); return *this; 79 | } 80 | inline Text& operator= (const std::string& rhs) { 81 | setFromUTF8String(rhs); return *this; 82 | } 83 | inline Text& operator= (const UChar& rhs) { 84 | assign(1, rhs); return *this; 85 | } 86 | inline Text& operator= (const Text& rhs) { 87 | assign(rhs); return *this; 88 | } 89 | 90 | // Combination operators 91 | inline Text& operator+ (const char* rhs) const { return Text(*this).appendUTF8String(rhs); } 92 | //inline Text& operator+= (const char* rhs) { return appendUTF8String(rhs); } 93 | 94 | // Convert Unicode character c to its UTF8 equivalent. 95 | // Returns an empty string on failure. 96 | static std::string UCharToUTF8String(const UChar c); 97 | 98 | // LF | CR 99 | inline static bool isLineSeparator(const UChar& c) { 100 | return c == 0x0a || c == 0x0d; 101 | } 102 | 103 | // SP | TAB 104 | inline static bool isWhitespace(const UChar& c) { 105 | return c == 0x20 || c == 0x09; 106 | } 107 | 108 | // SP | TAB | LF | CR 109 | inline static bool isWhitespaceOrLineSeparator(const UChar& c) { 110 | return isWhitespace(c) || isLineSeparator(c); 111 | } 112 | 113 | // 0-9 114 | inline static bool isDecimalDigit(const UChar& c) { 115 | return (c < 0x3a && c > 0x2f) // ascii 0-9 116 | || (c < 0xff1a && c > 0xff0f) // fullwidth 0-9 117 | ; 118 | } 119 | 120 | // 0-9 | A-F 121 | inline static bool isUpperHexDigit(const UChar& c) { 122 | return isDecimalDigit(c) 123 | || (c < 0x47 && c > 0x40) // A-F 124 | || (c < 0xff27 && c > 0xff20) // fullwidth A-F 125 | ; 126 | } 127 | 128 | // 0-9 | a-f 129 | inline static bool isLowerHexDigit(const UChar& c) { 130 | return isDecimalDigit(c) 131 | || (c < 0x67 && c > 0x60) // a-f 132 | || (c < 0xff47 && c > 0xff40) // fullwidth a-f 133 | ; 134 | } 135 | 136 | // 0-9 | A-F | a-f 137 | inline static bool isHexDigit(const UChar& c) { 138 | return isUpperHexDigit(c) 139 | || (c < 0x67 && c > 0x60) // a-f 140 | || (c < 0xff47 && c > 0xff40) // fullwidth a-f 141 | ; 142 | } 143 | 144 | inline static bool isPrintableASCII(const UChar& c) { 145 | return c < 0x7f && c > 0x20; 146 | } 147 | 148 | inline static bool isPrintable(const UChar& c) { 149 | // TODO: Actual list of printable chars in Unicode 6.1 (ZOMG that's a long list of tests) 150 | return isPrintableASCII(c) || c > 0x7f; 151 | } 152 | }; 153 | 154 | extern const UChar NullChar; 155 | 156 | } // namespace hue 157 | 158 | // std::ostream operator so we can write Text objects to an ostream (as UTF-8) 159 | inline static std::ostream& operator<< (std::ostream& os, const hue::Text& text) { 160 | return os << text.toString(); 161 | } 162 | 163 | // inline static Text& operator+= (Text& lhs, const std::string& rhs) { 164 | // lhs.reset(); 165 | // lhs 166 | // return lhs; 167 | // } 168 | 169 | #endif // _HUE_TEXT_INCLUDED 170 | -------------------------------------------------------------------------------- /src/ast/BinaryOp.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #ifndef HUE_AST_BINARYOP_H 5 | #define HUE_AST_BINARYOP_H 6 | 7 | #include "Expression.h" 8 | 9 | namespace hue { namespace ast { 10 | 11 | // Binary operators. 12 | class BinaryOp : public Expression { 13 | public: 14 | enum Kind { 15 | SimpleLTR = 0, // '=', '+', '>', '&', etc -- operator_ holds the value 16 | EqualityLTR, // '<=' '>=' '!=' '==' -- operator_ holds the value of the first byte 17 | }; 18 | 19 | BinaryOp(char op, Expression *lhs, Expression *rhs, Kind kind) 20 | : Expression(TBinaryOp, Type::Bool), operator_(op) , lhs_(lhs) , rhs_(rhs), kind_(kind) {} 21 | 22 | inline Kind kind() const { return kind_; } 23 | inline bool isEqualityLTRKind() const { return kind_ == EqualityLTR; } 24 | inline bool isComparison() const { 25 | return isEqualityLTRKind() || operator_ == '<' || operator_ == '>'; 26 | } 27 | inline char operatorValue() const { return operator_; } 28 | Expression *lhs() const { return lhs_; } 29 | Expression *rhs() const { return rhs_; } 30 | 31 | virtual const Type *resultType() const { 32 | if (isComparison()) { 33 | return resultType_; // always Type::Bool 34 | } else { 35 | return Type::highestFidelity(lhs_->resultType(), rhs_->resultType()); 36 | } 37 | } 38 | 39 | virtual void setResultType(const Type* T) { 40 | assert(T->isUnknown() == false); // makes no sense to set T=unknown 41 | // Call setResultType with T for LHS and RHS which are unknown 42 | if (lhs_ && lhs_->resultType()->isUnknown()) { 43 | lhs_->setResultType(T); 44 | } 45 | if (rhs_ && rhs_->resultType()->isUnknown()) { 46 | rhs_->setResultType(T); 47 | } 48 | } 49 | 50 | std::string operatorName() const { 51 | if (kind_ == EqualityLTR) { 52 | return std::string(1, '=') + operator_; 53 | } else { 54 | return std::string(1, operator_); 55 | } 56 | } 57 | 58 | virtual std::string toString(int level = 0) const { 59 | std::ostringstream ss; 60 | //NodeToStringHeader(level, ss); 61 | ss << "("; 62 | if (kind_ == EqualityLTR) ss << '='; 63 | ss << operator_ << " " 64 | << (lhs_ ? lhs_->toString(level+1) : "nil") 65 | << " " 66 | << (rhs_ ? rhs_->toString(level+1) : "nil") 67 | << ")"; 68 | return ss.str(); 69 | } 70 | private: 71 | char operator_; 72 | Expression *lhs_, *rhs_; 73 | Kind kind_; 74 | }; 75 | 76 | 77 | }} // namespace hue::ast 78 | #endif // HUE_AST_BINARYOP_H 79 | -------------------------------------------------------------------------------- /src/ast/Block.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | #ifndef HUE__AST_BLOCK_H 5 | #define HUE__AST_BLOCK_H 6 | #include "Expression.h" 7 | #include "../Logger.h" 8 | #include 9 | 10 | namespace hue { namespace ast { 11 | 12 | class Block : public Expression { 13 | public: 14 | Block() : Expression(TBlock) {} 15 | Block(const Type* resultType) : Expression(TBlock, resultType) {} 16 | Block(Expression *expression) : Expression(TBlock), expressions_(1, expression) {} 17 | Block(const ExpressionList &expressions) : Expression(TBlock), expressions_(expressions) {} 18 | 19 | const ExpressionList& expressions() const { return expressions_; }; 20 | void addExpression(Expression *expression) { expressions_.push_back(expression); }; 21 | 22 | virtual const Type *resultType() const { 23 | if (expressions_.size() != 0) { 24 | return expressions_.back()->resultType(); 25 | } else { 26 | return resultType_; // Type::Unknown 27 | } 28 | } 29 | 30 | virtual void setResultType(const Type* T) { 31 | assert(T->isUnknown() == false); // makes no sense to set T=unknown 32 | // Call setResultType with T for last expression if the last expression is unknown 33 | if (expressions_.size() != 0) { 34 | expressions_.back()->setResultType(T); 35 | } 36 | } 37 | 38 | virtual std::string toString(int level = 0) const { 39 | std::ostringstream ss; 40 | //ss << "("; 41 | ExpressionList::const_iterator I = expressions_.begin(), E = expressions_.end(); 42 | if (I != E) { 43 | ss << (*I)->toString(level); 44 | ++I; 45 | } 46 | for (;I != E; ++I) { 47 | if (level == 0) ss << "\n"; 48 | else NodeToStringHeader(level, ss); 49 | ss << (*I)->toString(level); 50 | } 51 | //ss << ")"; 52 | return ss.str(); 53 | } 54 | 55 | // TODO: 56 | // virtual std::string toHueSource() const { 57 | // 58 | // } 59 | 60 | private: 61 | ExpressionList expressions_; 62 | }; 63 | 64 | }} // namespace hue.ast 65 | #endif // HUE__AST_BLOCK_H 66 | -------------------------------------------------------------------------------- /src/ast/Call.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #ifndef _HUE_AST_CALL_INCLUDED 5 | #define _HUE_AST_CALL_INCLUDED 6 | 7 | #include "Expression.h" 8 | #include "Function.h" 9 | 10 | namespace hue { namespace ast { 11 | 12 | // Function calls. 13 | class Call : public Expression { 14 | public: 15 | typedef std::vector ArgumentList; 16 | 17 | Call(Symbol* calleeSymbol, ArgumentList &args) 18 | : Expression(TCall), calleeSymbol_(calleeSymbol), args_(args), calleeType_(0) {} 19 | 20 | Symbol* symbol() const { return calleeSymbol_; } 21 | const ArgumentList& arguments() const { return args_; } 22 | 23 | const FunctionType* calleeType() const { return calleeType_; } 24 | void setCalleeType(const FunctionType* FT) { calleeType_ = FT; } 25 | 26 | virtual const Type *resultType() const { 27 | return calleeType_ ? calleeType_->resultType() : &UnknownType; 28 | } 29 | 30 | virtual void setResultType(const Type* T) { 31 | assert(T->isUnknown() == false); // makes no sense to set T=unknown 32 | // Call setResultType with T for callee if callee's resultType is unknown 33 | if (calleeType_ && calleeType_->resultType()->isUnknown()) { 34 | const_cast(calleeType_)->setResultType(T); 35 | } 36 | } 37 | 38 | virtual std::string toString(int level = 0) const { 39 | std::ostringstream ss; 40 | //NodeToStringHeader(level, ss); 41 | ss << "("; 42 | ss << calleeSymbol_; 43 | for (ArgumentList::const_iterator I = args_.begin(), E = args_.end(); I != E; ++I) { 44 | ss << " " << (*I)->toString(level+1); 45 | } 46 | ss << ")"; 47 | return ss.str(); 48 | } 49 | private: 50 | Symbol* calleeSymbol_; 51 | ArgumentList args_; 52 | const FunctionType* calleeType_; // weak 53 | }; 54 | 55 | }} // namespace hue::ast 56 | #endif // _HUE_AST_CALL_INCLUDED 57 | -------------------------------------------------------------------------------- /src/ast/Conditional.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | #ifndef HUE__AST_CONDITIONALS_H 5 | #define HUE__AST_CONDITIONALS_H 6 | #include "Expression.h" 7 | #include "Block.h" 8 | #include 9 | #include 10 | 11 | namespace hue { namespace ast { 12 | 13 | class Conditional : public Expression { 14 | public: 15 | Conditional() : Expression(TConditional), testExpression_(0), trueBlock_(0), falseBlock_(0) {} 16 | 17 | Expression* testExpression() const { return testExpression_; } 18 | void setTestExpression(Expression* expr) { testExpression_ = expr; } 19 | 20 | Block* trueBlock() const { return trueBlock_; } 21 | void setTrueBlock(Block* B) { trueBlock_ = B; } 22 | 23 | Block* falseBlock() const { return falseBlock_; } 24 | void setFalseBlock(Block* B) { falseBlock_ = B; } 25 | 26 | virtual const Type *resultType() const { 27 | assert(trueBlock_); 28 | const Type* trueT = trueBlock_->resultType(); 29 | const Type* falseT = falseBlock_->resultType(); 30 | return Type::highestFidelity(trueT, falseT); 31 | } 32 | 33 | virtual void setResultType(const Type* T) { 34 | assert(trueBlock_); 35 | trueBlock_->setResultType(T); 36 | assert(falseBlock_); 37 | falseBlock_->setResultType(T); 38 | } 39 | 40 | virtual std::string toString(int level = 0) const { 41 | std::ostringstream ss; 42 | //NodeToStringHeader(level, ss); 43 | ss << "(if " << (testExpression_ ? testExpression_->toString(level) : "nil"); 44 | NodeToStringHeader(level+1, ss); 45 | ss << (trueBlock_ ? trueBlock_->toString(level+1) : "nil"); 46 | if (level == 0) ss << "\n"; else NodeToStringHeader(level, ss); 47 | ss << "else "; 48 | NodeToStringHeader(level+1, ss); 49 | ss << (falseBlock_ ? falseBlock_->toString(level+1) : "nil") 50 | << ")"; 51 | return ss.str(); 52 | } 53 | 54 | private: 55 | Expression* testExpression_; 56 | Block* trueBlock_; 57 | Block* falseBlock_; 58 | }; 59 | 60 | }} // namespace hue.ast 61 | #endif // HUE__AST_CONDITIONALS_H 62 | -------------------------------------------------------------------------------- /src/ast/DataLiteral.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #ifndef HUE__AST_DATA_LITERAL_H 4 | #define HUE__AST_DATA_LITERAL_H 5 | #include "Expression.h" 6 | #include 7 | #include 8 | 9 | namespace hue { namespace ast { 10 | 11 | class DataLiteral : public Expression { 12 | public: 13 | DataLiteral(const ByteString& data) 14 | : Expression(TDataLiteral, ArrayType::get(ByteType)), data_(data) {} 15 | 16 | inline const ByteString& data() const { return data_; }; 17 | 18 | virtual std::string toString(int level = 0) const { 19 | std::ostringstream ss; 20 | NodeToStringHeader(level, ss); 21 | ss << "'"; 22 | ByteString::const_iterator it = data_.begin(); 23 | 24 | for (; it != data_.end(); ++ it) { 25 | uint8_t c = *it; 26 | if (c == '\\') { 27 | ss << "\\\\"; 28 | } else if (c == '\'') { 29 | ss << "\\'"; 30 | } else if (Text::isPrintableASCII(c)) { 31 | ss << (char)c; 32 | } else { 33 | ss.flags(std::ios::hex); 34 | ss << (c < 0x10 ? "\\x0" : "\\x") << (uint16_t)c; 35 | ss.flags(); 36 | } 37 | } 38 | 39 | ss << "'"; 40 | return ss.str(); 41 | } 42 | 43 | private: 44 | ByteString data_; 45 | }; 46 | 47 | }} // namespace hue.ast 48 | #endif // HUE__AST_DATA_LITERAL_H 49 | -------------------------------------------------------------------------------- /src/ast/Expression.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | // Expressions 5 | #ifndef HUE__AST_EXPRESSION_H 6 | #define HUE__AST_EXPRESSION_H 7 | 8 | #include "Node.h" 9 | #include "Type.h" 10 | #include "Variable.h" 11 | #include "../Logger.h" 12 | #include "../Text.h" 13 | 14 | #include 15 | 16 | namespace hue { namespace ast { 17 | 18 | class FunctionType; 19 | 20 | class Expression; 21 | typedef std::vector ExpressionList; 22 | 23 | // Base class for all expression nodes. 24 | class Expression : public Node { 25 | public: 26 | Expression(NodeTypeID t, const Type* resultType) : Node(t), resultType_(resultType) {} 27 | Expression(NodeTypeID t = TExpression, Type::TypeID resultTypeID = Type::Unknown) 28 | : Node(t), resultType_(new Type(resultTypeID)) {} 29 | virtual ~Expression() {} 30 | 31 | // Type of result from this expression 32 | virtual const Type *resultType() const { return resultType_; } 33 | virtual void setResultType(const Type* T) { 34 | resultType_ = T; 35 | } 36 | 37 | virtual std::string toString(int level = 0) const { 38 | std::ostringstream ss; 39 | ss << "(?)"; 40 | return ss.str(); 41 | } 42 | 43 | protected: 44 | const Type* resultType_; 45 | }; 46 | 47 | // Numeric integer literals like "3". 48 | class IntLiteral : public Expression { 49 | Text value_; 50 | const uint8_t radix_; 51 | public: 52 | IntLiteral(Text value, uint8_t radix = 10) 53 | : Expression(TIntLiteral, Type::Int), value_(value), radix_(radix) {} 54 | 55 | const Text& text() const { return value_; } 56 | const uint8_t& radix() const { return radix_; } 57 | 58 | virtual std::string toString(int level = 0) const { 59 | std::ostringstream ss; 60 | ss << value_; 61 | return ss.str(); 62 | } 63 | }; 64 | 65 | // Numeric fractional literals like "1.2". 66 | class FloatLiteral : public Expression { 67 | Text value_; 68 | public: 69 | FloatLiteral(Text value) : Expression(TFloatLiteral, Type::Float), value_(value) {} 70 | const Text& text() const { return value_; } 71 | virtual std::string toString(int level = 0) const { 72 | std::ostringstream ss; 73 | ss << value_; 74 | return ss.str(); 75 | } 76 | }; 77 | 78 | // Boolean literal, namely "true" or "false" 79 | class BoolLiteral : public Expression { 80 | bool value_; 81 | public: 82 | BoolLiteral(bool value) : Expression(TBoolLiteral, Type::Bool), value_(value) {} 83 | inline bool isTrue() const { return value_; } 84 | virtual std::string toString(int level = 0) const { 85 | std::ostringstream ss; 86 | ss << (value_ ? "true" : "false"); 87 | return ss.str(); 88 | } 89 | }; 90 | 91 | /// Assigning a value to a symbol or variable, e.g. foo = 5 92 | class Assignment : public Expression { 93 | public: 94 | 95 | Assignment(Variable *var, Expression *rhs) 96 | : Expression(TAssignment), var_(var), rhs_(rhs) {} 97 | 98 | const Variable* variable() const { return var_; }; 99 | Expression* rhs() const { return rhs_; } 100 | 101 | virtual const Type *resultType() const { 102 | if (rhs_ && var_->hasUnknownType()) { 103 | // rloge("CASE 1 ret " << rhs_->resultType()->toString() 104 | // << " from " << rhs_->toString() << " (" << rhs_->typeName() << ")"); 105 | return rhs_->resultType(); 106 | } else { 107 | //rloge("CASE 2 ret " << var_->type()->toString()); 108 | return var_->type(); 109 | } 110 | } 111 | 112 | virtual void setResultType(const Type* T) throw(std::logic_error) { 113 | throw std::logic_error("Can not set type for compound 'Assignment' expression"); 114 | } 115 | 116 | virtual std::string toString(int level = 0) const { 117 | std::ostringstream ss; 118 | //NodeToStringHeader(level, ss); 119 | ss << "(= " 120 | << var_->toString(level+1) 121 | << " " 122 | << rhs_->toString(level+1) 123 | << ')'; 124 | return ss.str(); 125 | } 126 | private: 127 | Variable* var_; 128 | Expression* rhs_; 129 | }; 130 | 131 | 132 | }} // namespace hue::ast 133 | #endif // HUE__AST_EXPRESSION_H 134 | -------------------------------------------------------------------------------- /src/ast/Function.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #ifndef HUE__AST_PROTOTYPE_H 5 | #define HUE__AST_PROTOTYPE_H 6 | #include "Node.h" 7 | #include "Expression.h" 8 | #include "Type.h" 9 | #include "FunctionType.h" 10 | #include "Block.h" 11 | 12 | namespace hue { namespace ast { 13 | 14 | class Argument { 15 | public: 16 | Text identifier; 17 | Type type; 18 | 19 | Argument(Text identifier, const Type& type) 20 | : identifier(identifier), type(type) {} 21 | 22 | Argument(Text identifier) : identifier(identifier), type(Type::Unknown) {} 23 | 24 | std::string toString() const { 25 | return identifier.UTF8String() + " " + type.toString(); 26 | } 27 | }; 28 | 29 | // Represents a function definition. 30 | class Function : public Expression { 31 | FunctionType *functionType_; 32 | Block *body_; 33 | public: 34 | Function(FunctionType *functionType, Block *body) 35 | : Expression(TFunction), functionType_(functionType), body_(body) {} 36 | Function(FunctionType *functionType, Expression *body) 37 | : Expression(TFunction), functionType_(functionType), body_(new Block(body)) {} 38 | 39 | FunctionType *functionType() const { return functionType_; } 40 | Block *body() const { return body_; } 41 | 42 | // Override Expression result type 43 | virtual const Type *resultType() const { 44 | return functionType_; 45 | } 46 | virtual void setResultType(const Type* T) throw(std::logic_error) { 47 | throw std::logic_error("Can not set type for compound 'Function' expression"); 48 | } 49 | 50 | // Type resulting from a call to this function 51 | const Type *callResultType() const { 52 | return functionType_ ? functionType_->resultType() : &UnknownType; 53 | } 54 | 55 | virtual std::string toString(int level = 0) const { 56 | std::ostringstream ss; 57 | //NodeToStringHeader(level, ss); 58 | ss << '(' << (functionType_ ? functionType_->toString(level) : "") 59 | << " "; 60 | NodeToStringHeader(level, ss); 61 | ss << (body_ ? body_->toString(level) : "nil") 62 | << ')'; 63 | return ss.str(); 64 | } 65 | }; 66 | 67 | // Represents an external function declaration. 68 | // TODO: Join Function and ExternalFunction classes 69 | class ExternalFunction : public Expression { 70 | Text name_; 71 | FunctionType *functionType_; 72 | public: 73 | ExternalFunction(const Text &name, FunctionType *functionType) 74 | : Expression(TExternalFunction), name_(name), functionType_(functionType) {} 75 | 76 | inline const Text& name() const { return name_; } 77 | inline FunctionType *functionType() const { return functionType_; } 78 | 79 | // Override Expression result type 80 | virtual const Type *resultType() const { 81 | return functionType_ ? functionType_->resultType() : 0; 82 | } 83 | virtual void setResultType(const Type* T) { 84 | if (functionType_) functionType_->setResultType(T); 85 | } 86 | 87 | virtual std::string toString(int level = 0) const { 88 | std::ostringstream ss; 89 | NodeToStringHeader(level, ss); 90 | ss << "toString(level+1) : "") 92 | << '>'; 93 | return ss.str(); 94 | } 95 | }; 96 | 97 | }} // namespace hue.ast 98 | #endif // HUE__AST_PROTOTYPE_H 99 | -------------------------------------------------------------------------------- /src/ast/FunctionType.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "FunctionType.h" 4 | #include 5 | 6 | namespace hue { namespace ast { 7 | 8 | std::string FunctionType::toString(int level) const { 9 | std::ostringstream ss; 10 | //NodeToStringHeader(level, ss); 11 | ss << "func ("; 12 | if (args_) { 13 | VariableList::const_iterator it1; 14 | it1 = args_->begin(); 15 | if (it1 < args_->end()) { ss << (*it1)->toString(); it1++; } 16 | for (; it1 < args_->end(); it1++) { ss << ", " << (*it1)->toString(); } 17 | } 18 | ss << ")"; 19 | 20 | if (resultType_) ss << ' ' << resultType_->toString(); 21 | return ss.str(); 22 | } 23 | 24 | 25 | std::string FunctionType::toHueSource() const { 26 | std::ostringstream ss; 27 | ss << "func "; 28 | 29 | if (args_ && !args_->empty()) { 30 | ss << '('; 31 | 32 | for (VariableList::iterator I = args_->begin(), E = args_->end(); I != E; ++I) { 33 | assert((*I) != 0); 34 | if ((*I)->hasUnknownType()) { 35 | ss << "?"; 36 | } else { 37 | ss << (*I)->type()->toHueSource(); 38 | } 39 | if (I != E) ss << ", "; 40 | } 41 | ss << ')'; 42 | } 43 | 44 | if (resultType_) 45 | ss << ' ' << resultType_->toHueSource(); 46 | 47 | return ss.str(); 48 | } 49 | 50 | }} // namespace hue::ast 51 | -------------------------------------------------------------------------------- /src/ast/FunctionType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #ifndef HUE_AST_FUNCTION_TYPE_H 4 | #define HUE_AST_FUNCTION_TYPE_H 5 | 6 | #include "Type.h" 7 | #include "Variable.h" 8 | #include 9 | #include 10 | #include 11 | 12 | namespace hue { namespace ast { 13 | 14 | // Represents the "prototype" for a function, which captures its name, and its 15 | // argument names (thus implicitly the number of arguments the function takes). 16 | class FunctionType : public Type { 17 | public: 18 | FunctionType(VariableList *args = 0, 19 | const Type *resultType = 0, 20 | bool isPublic = false) 21 | : Type(FuncT), args_(args), resultType_(resultType), isPublic_(isPublic) {} 22 | 23 | VariableList *args() const { return args_; } 24 | 25 | const Type *resultType() const { return resultType_; } 26 | void setResultType(const Type* T) { resultType_ = T; } 27 | 28 | bool resultTypeIsUnknown() const { return resultType_ && resultType_->isUnknown(); } 29 | 30 | bool isPublic() const { return isPublic_; } 31 | void setIsPublic(bool isPublic) { isPublic_ = isPublic; } 32 | 33 | std::string toString(int level = 0) const; 34 | virtual std::string toString() const { return toString(0); } 35 | virtual std::string toHueSource() const; 36 | 37 | private: 38 | VariableList *args_; 39 | const Type *resultType_; 40 | bool isPublic_; 41 | }; 42 | 43 | }} // namespace hue::ast 44 | #endif // HUE_AST_FUNCTION_TYPE_H 45 | -------------------------------------------------------------------------------- /src/ast/ListLiteral.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #ifndef HUE__AST_LIST_LITERAL_H 5 | #define HUE__AST_LIST_LITERAL_H 6 | #include "Block.h" 7 | 8 | namespace hue { namespace ast { 9 | 10 | class ListLiteral : public Expression { 11 | public: 12 | ListLiteral() : Expression(TListLiteral, ArrayType::get(UnknownType)) {} 13 | const ExpressionList& expressions() const { return expressions_; }; 14 | void addExpression(Expression *expression) { expressions_.push_back(expression); }; 15 | 16 | virtual std::string toString(int level = 0) const { 17 | std::ostringstream ss; 18 | ss << "toString(level+1); 23 | it1++; 24 | } 25 | for (; it1 < expressions_.end(); it1++) { 26 | ss << ", " << (*it1)->toString(level+1); 27 | } 28 | ss << "]>"; 29 | return ss.str(); 30 | } 31 | 32 | private: 33 | ExpressionList expressions_; 34 | }; 35 | 36 | }} // namespace hue.ast 37 | #endif // HUE__AST_LIST_LITERAL_H 38 | -------------------------------------------------------------------------------- /src/ast/Node.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | // Base class for all expression nodes. 5 | #ifndef HUE__AST_NODE_H 6 | #define HUE__AST_NODE_H 7 | 8 | #include "Type.h" 9 | #include 10 | #include 11 | 12 | namespace hue { namespace ast { 13 | 14 | inline static void NodeToStringHeader(int level, std::ostream& ss) { 15 | if (level > 0) { 16 | ss << std::endl; 17 | for (int i=level; i--; ) ss << " "; 18 | } 19 | } 20 | 21 | class Node; 22 | typedef std::vector NodeList; 23 | 24 | class Node { 25 | public: 26 | enum NodeTypeID { 27 | TNode, 28 | 29 | TFunctionType, 30 | TValue, 31 | 32 | // Expressions 33 | TExpression, 34 | TFunction, 35 | TExternalFunction, 36 | TBlock, 37 | TSymbol, 38 | TAssignment, 39 | TBinaryOp, 40 | TCall, 41 | TConditional, 42 | TIntLiteral, 43 | TFloatLiteral, 44 | TBoolLiteral, 45 | TDataLiteral, 46 | TTextLiteral, 47 | TListLiteral, 48 | TStructure, 49 | 50 | _TypeCount 51 | }; 52 | 53 | Node(NodeTypeID t = TNode) : type_(t) {} 54 | virtual ~Node() {} 55 | 56 | inline const NodeTypeID& nodeTypeID() const { return type_; } 57 | 58 | inline bool isFunctionType() const { return type_ == TFunctionType; } 59 | inline bool isValue() const { return type_ == TValue; } 60 | 61 | inline bool isExpression() const { return type_ >= TExpression; } 62 | inline bool isFunction() const { return type_ == TFunction; } 63 | inline bool isExternalFunction() const { return type_ == TExternalFunction; } 64 | inline bool isCall() const { return type_ == TCall; } 65 | inline bool isBlock() const { return type_ == TBlock; } 66 | inline bool isSymbol() const { return type_ == TSymbol; } 67 | inline bool isAssignment() const { return type_ == TAssignment; } 68 | 69 | inline bool isStructure() const { return type_ == TStructure; } 70 | 71 | inline bool isCallable() const { return isFunction() || isExternalFunction(); } 72 | 73 | virtual std::string toString(int level = 0) const { 74 | std::ostringstream ss; NodeToStringHeader(level, ss); ss << ""; 75 | return ss.str(); 76 | } 77 | 78 | virtual const char* typeName() const { 79 | switch (type_) { 80 | case TFunctionType: return "FunctionType"; 81 | case TValue: return "Value"; 82 | 83 | // Expressions 84 | case TExpression: return "Expression"; 85 | case TFunction: return "Function"; 86 | case TExternalFunction: return "ExternalFunction"; 87 | case TBlock: return "Block"; 88 | case TSymbol: return "Symbol"; 89 | case TAssignment: return "Assignment"; 90 | case TBinaryOp: return "BinaryOp"; 91 | case TCall: return "Call"; 92 | case TConditional: return "Conditional"; 93 | case TIntLiteral: return "IntLiteral"; 94 | case TFloatLiteral: return "FloatLiteral"; 95 | case TBoolLiteral: return "BoolLiteral"; 96 | case TDataLiteral: return "DataLiteral"; 97 | case TTextLiteral: return "TextLiteral"; 98 | case TListLiteral: return "ListLiteral"; 99 | case TStructure: return "Structure"; 100 | 101 | default: return "?"; 102 | } 103 | } 104 | 105 | private: 106 | const NodeTypeID type_; 107 | }; 108 | 109 | // Used for function input parameters 110 | class Value : public Node { 111 | public: 112 | Value(const Type* T) : Node(TValue), type_(T) {} 113 | inline const Type* resultType() const { return type_; } 114 | protected: 115 | const Type* type_; 116 | }; 117 | 118 | }} // namespace hue.ast 119 | 120 | inline static std::ostream& operator<< (std::ostream& os, const hue::ast::Node& node) { 121 | return os << node.toString(); 122 | } 123 | inline static std::ostream& operator<< (std::ostream& os, const hue::ast::Node* node) { 124 | return os << node->toString(); 125 | } 126 | 127 | #endif // HUE__AST_NODE_H 128 | -------------------------------------------------------------------------------- /src/ast/StructType.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "StructType.h" 4 | #include "Function.h" 5 | #include "Block.h" 6 | #include "../Mangle.h" 7 | 8 | namespace hue { namespace ast { 9 | 10 | //static 11 | // StructType* StructType::get(const TypeList& types) { 12 | // // TODO reuse 13 | // StructType* ST = new StructType; 14 | // ST->types_.assign(types.begin(), types.end()); 15 | // return ST; 16 | // } 17 | 18 | 19 | //static 20 | StructType* StructType::get(const Member::List& members) { 21 | // TODO reuse 22 | StructType* ST = new StructType; 23 | ST->types_.reserve(members.size()); 24 | 25 | for (Member::List::const_iterator I = members.begin(), E = members.end(); I != E; ++I) { 26 | ST->nameToIndexMap_[(*I).name] = ST->types_.size(); 27 | //rlogw("StructType::get: push " << (*I).name << "," << (*I).type->toString()); 28 | ST->types_.push_back((*I).type); 29 | } 30 | 31 | return ST; 32 | } 33 | 34 | 35 | std::string StructType::toString() const { 36 | // This is kind of inefficient... 37 | // Create index-to-name map 38 | size_t i = 0; 39 | std::vector orderedNames; 40 | orderedNames.reserve(types_.size()); 41 | 42 | for (NameMap::const_iterator I = nameToIndexMap_.begin(), E = nameToIndexMap_.end(); 43 | I != E; ++I) 44 | { 45 | orderedNames[i++] = &(I->first); 46 | } 47 | 48 | std::string s("{"); 49 | for (size_t i = 0, L = size(); i < L; ++i ) { 50 | s += orderedNames[i]->UTF8String() + ":" + types_[i]->toString(); 51 | if (i != L-1) s += " "; 52 | } 53 | return s + "}"; 54 | } 55 | 56 | 57 | std::string StructType::canonicalName() const { 58 | return std::string("type.") + mangle(*this); 59 | } 60 | 61 | 62 | size_t StructType::indexOf(const Text& name) const { 63 | NameMap::const_iterator it = nameToIndexMap_.find(name); 64 | if (it != nameToIndexMap_.end()) { 65 | return it->second; 66 | } else { 67 | return SIZE_MAX; 68 | } 69 | } 70 | 71 | 72 | const Type* StructType::operator[](const Text& name) const { 73 | NameMap::const_iterator it = nameToIndexMap_.find(name); 74 | if (it != nameToIndexMap_.end()) { 75 | return types_[it->second]; 76 | } else { 77 | return 0; 78 | } 79 | } 80 | 81 | }} // namespace hue::ast 82 | -------------------------------------------------------------------------------- /src/ast/StructType.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #ifndef HUE_AST_STRUCT_TYPE_H 4 | #define HUE_AST_STRUCT_TYPE_H 5 | 6 | #include "Type.h" 7 | #include 8 | #include 9 | #include 10 | 11 | namespace hue { namespace ast { 12 | 13 | class Block; 14 | class FunctionType; 15 | 16 | // A struct type represents an ordered map where the offset of a member 17 | // signifies the offset into the underlying struct. The name is the name 18 | // of the member and is primarily used for debugging. 19 | 20 | // struct 21 | // foo = 1 22 | // bar = 2.3 23 | // --> 24 | // StructType 25 | // types_[Int, Float] 26 | // names_["foo", "bar"] 27 | // 28 | 29 | class StructType : public Type { 30 | typedef std::map NameMap; 31 | StructType() : Type(StructureT) {} 32 | 33 | public: 34 | class Member { 35 | public: 36 | typedef std::vector List; 37 | 38 | Member() : type(0), name() {} 39 | Member(const Type* T, const Text N, unsigned i) : type(T), name(N), index(i) {} 40 | //Member(const Member& other) : type(other.type), ... , name(other.name) {} 41 | 42 | const Type* type; 43 | Text name; 44 | unsigned index; 45 | 46 | // inline Member& operator= (const Member& rhs) { 47 | // rhs 48 | // return *this; 49 | // } 50 | }; 51 | 52 | //static StructType* get(const TypeList& types); 53 | static StructType* get(const Member::List& members); 54 | 55 | inline size_t size() const { return types_.size(); } 56 | const TypeList& types() const { return types_; } 57 | bool isPacked() const { return true; } 58 | 59 | virtual std::string toString() const; 60 | virtual std::string canonicalName() const; 61 | 62 | // Struct offset for member with name. Returns SIZE_MAX if not found. 63 | size_t indexOf(const Text& name) const; 64 | 65 | // Get type for name (or nil if not found) 66 | const Type* operator[](const Text& name) const; 67 | 68 | private: 69 | TypeList types_; 70 | NameMap nameToIndexMap_; 71 | }; 72 | 73 | }} // namespace hue::ast 74 | #endif // HUE_AST_STRUCT_TYPE_H 75 | -------------------------------------------------------------------------------- /src/ast/Structure.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "Structure.h" 4 | 5 | namespace hue { namespace ast { 6 | 7 | // size_t Structure::indexOf(const Text& name) const { 8 | // NameMap::const_iterator it = nameMap_.find(name); 9 | // if (it != nameMap_.end()) { 10 | // return it->second; 11 | // } else { 12 | // return SIZE_MAX; 13 | // } 14 | // } 15 | 16 | void Structure::update() { 17 | const ExpressionList& expressions = block_->expressions(); 18 | 19 | StructType::Member::List stmembers; 20 | stmembers.reserve(expressions.size()); 21 | 22 | members_.clear(); 23 | 24 | ExpressionList::const_iterator I = expressions.begin(), E = expressions.end(); 25 | for (;I != E; ++I) { 26 | const Expression* expr = *I; 27 | assert(expr->isAssignment()); 28 | const Assignment* ass = static_cast(expr); 29 | const Text& name = ass->variable()->name(); 30 | 31 | size_t index = stmembers.size(); 32 | stmembers.push_back(StructType::Member(ass->resultType(), name, (unsigned)index)); 33 | 34 | Member& member = members_[name]; 35 | member.index = (unsigned)index; 36 | member.value = ass->rhs(); 37 | } 38 | 39 | structType_ = StructType::get(stmembers); 40 | } 41 | 42 | 43 | const Structure::Member* Structure::operator[](const Text& name) const { 44 | MemberMap::const_iterator it = members_.find(name); 45 | if (it != members_.end()) { 46 | return &(it->second); 47 | } else { 48 | return 0; 49 | } 50 | } 51 | 52 | 53 | 54 | }} // namespace hue::ast 55 | -------------------------------------------------------------------------------- /src/ast/Structure.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | #ifndef HUE_AST_STRUCTURE_H 5 | #define HUE_AST_STRUCTURE_H 6 | #include "StructType.h" 7 | #include "Expression.h" 8 | #include "Block.h" 9 | #include 10 | #include 11 | #include 12 | 13 | namespace hue { namespace ast { 14 | 15 | class Structure : public Expression { 16 | public: 17 | class Member { 18 | public: 19 | Member() : index(0), value(0) {} 20 | unsigned index; 21 | Expression* value; 22 | }; 23 | 24 | typedef std::map MemberMap; 25 | 26 | Structure(Block* block = 0) : Expression(TStructure), block_(0), structType_(0) { 27 | setBlock(block); 28 | } 29 | 30 | Block* block() const { return block_; } 31 | void setBlock(Block* B) { 32 | block_ = B; 33 | update(); 34 | } 35 | 36 | void update(); 37 | 38 | const StructType *resultStructType() const { return structType_; } 39 | virtual const Type *resultType() const { return resultStructType(); } 40 | virtual void setResultType(const Type* T) throw(std::logic_error) { 41 | throw std::logic_error("Can not set type for 'struct' expression"); 42 | } 43 | 44 | // Get member for name (or nil if not found) 45 | const Member* operator[](const Text& name) const; 46 | 47 | virtual std::string toString(int level = 0) const { 48 | std::ostringstream ss; 49 | ss << "(struct "; 50 | NodeToStringHeader(level+1, ss); 51 | ss << (block_ ? block_->toString(level+1) : "nil") 52 | << ")"; 53 | return ss.str(); 54 | } 55 | 56 | private: 57 | Block* block_; 58 | StructType* structType_; 59 | MemberMap members_; 60 | }; 61 | 62 | }} // namespace hue.ast 63 | #endif // HUE_AST_STRUCTURE_H 64 | -------------------------------------------------------------------------------- /src/ast/Symbol.cc: -------------------------------------------------------------------------------- 1 | #include "Symbol.h" 2 | #include "Function.h" 3 | #include "../Logger.h" 4 | #include 5 | 6 | namespace hue { namespace ast { 7 | 8 | 9 | Symbol::Symbol(const Text &name, bool isPath) : Expression(TSymbol) { 10 | if (!isPath) { 11 | pathname_.push_back(name); 12 | } else { 13 | pathname_ = name.split(':'); 14 | } 15 | } 16 | 17 | 18 | std::string Symbol::toString(int level) const { 19 | if (pathname_.size() == 0) { 20 | return ""; 21 | } else if (pathname_.size() == 1) { 22 | return pathname_[0].UTF8String(); 23 | } else { 24 | return Text(":").join(pathname_).UTF8String(); 25 | } 26 | } 27 | 28 | 29 | // From when we kept a ref to the value: 30 | // const Type *Symbol::resultType() const { 31 | // if (value_ && value_->isExpression()) { 32 | // return static_cast(value_)->resultType(); 33 | // } else if (value_ && value_->isFunctionType()) { 34 | // return static_cast(value_)->resultType(); 35 | // } else if (value_ && value_->isVariable()) { 36 | // Variable* var = static_cast(value_); 37 | // return var->type() ? var->type() : resultType_; 38 | // } else { 39 | // return resultType_; 40 | // } 41 | // } 42 | 43 | // void Symbol::setResultType(const Type* T) { 44 | // assert(T->isUnknown() == false); // makes no sense to set T=unknown 45 | 46 | // // Call setResultType with T for value_ if value_ result type is unknown 47 | // if (value_) { 48 | 49 | // if (value_->isExpression()) { 50 | // Expression* expr = static_cast(value_); 51 | // if (expr->resultType()->isUnknown()) 52 | // expr->setResultType(T); 53 | 54 | // } else if (value_->isFunctionType()) { 55 | // FunctionType* FT = static_cast(value_); 56 | // if (FT->resultType()->isUnknown()) 57 | // FT->setResultType(T); 58 | 59 | // } else if (value_->isVariable()) { 60 | // Variable* var = static_cast(value_); 61 | // if (!var->type() || var->type()->isUnknown()) 62 | // var->setType(T); 63 | // } 64 | 65 | // } else { 66 | // resultType_ = T; 67 | // } 68 | // } 69 | 70 | }} // namespace hue::ast 71 | -------------------------------------------------------------------------------- /src/ast/Symbol.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #ifndef HUE_AST_SYMBOL_H 4 | #define HUE_AST_SYMBOL_H 5 | 6 | #include "Expression.h" 7 | 8 | namespace hue { namespace ast { 9 | 10 | // Representes a symbolic reference, like "a" or "foo:bar". 11 | class Symbol : public Expression { 12 | public: 13 | Symbol(const Text &name, bool isPath); 14 | 15 | //const Text& name() const { return pathname_.size() == 0 ? Text::Empty : pathname_[0]; } 16 | const Text::List& pathname() const { return pathname_; } 17 | bool isPath() const { return pathname_.size() > 1; } 18 | virtual std::string toString(int level = 0) const; 19 | 20 | protected: 21 | Text::List pathname_; 22 | }; 23 | 24 | 25 | }} // namespace hue::ast 26 | #endif // HUE_AST_SYMBOL_H 27 | -------------------------------------------------------------------------------- /src/ast/TextLiteral.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #ifndef HUE__AST_TEXT_LITERAL_H 5 | #define HUE__AST_TEXT_LITERAL_H 6 | #include "Expression.h" 7 | #include "../utf8/checked.h" 8 | 9 | namespace hue { namespace ast { 10 | 11 | class TextLiteral : public Expression { 12 | public: 13 | TextLiteral(const Text& text) 14 | : Expression(TTextLiteral, ArrayType::get(CharType)), text_(text) {} 15 | const Text& text() const { return text_; } 16 | 17 | virtual std::string toString(int level = 0) const { 18 | std::ostringstream ss; 19 | NodeToStringHeader(level, ss); 20 | ss << "\""; 21 | Text::const_iterator it = text_.begin(); 22 | 23 | for (; it != text_.end(); ++ it) { 24 | UChar c = *it; 25 | if (c == '\\') { 26 | ss << "\\\\"; 27 | } else if (c == '"') { 28 | ss << "\\\""; 29 | } else if (c == 0x0a) { 30 | ss << "\\n"; 31 | } else if (c == 0x0d) { 32 | ss << "\\r"; 33 | } else if (c == 0x09) { 34 | ss << "\\t"; 35 | } else if (Text::isPrintable(c) || Text::isWhitespace(c)) { 36 | ss << Text::UCharToUTF8String(c); 37 | } else { 38 | ss.flags(std::ios::hex); 39 | ss << "\\u" << c; 40 | ss.flags(); 41 | } 42 | } 43 | 44 | ss << "\""; 45 | return ss.str(); 46 | } 47 | 48 | private: 49 | Text text_; 50 | }; 51 | 52 | }} // namespace hue.ast 53 | #endif // HUE__AST_TEXT_LITERAL_H 54 | -------------------------------------------------------------------------------- /src/ast/Type.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "Type.h" 4 | 5 | namespace hue { namespace ast { 6 | 7 | const Type UnknownType(Type::Unknown); 8 | const Type NilType(Type::Nil); 9 | const Type FloatType(Type::Float); 10 | const Type IntType(Type::Int); 11 | const Type CharType(Type::Char); 12 | const Type ByteType(Type::Byte); 13 | const Type BoolType(Type::Bool); 14 | //const Type FuncType(Type::Func); 15 | 16 | const Type* Type::highestFidelity(const Type* T1, const Type* T2) { 17 | if (T1 && !T1->isUnknown() && T2 && !T2->isUnknown()) { 18 | if (T1 == T2 || T1->isEqual(*T2)) { 19 | return T1; 20 | } else if (T1->isInt() && T2->isFloat()) { 21 | return T2; 22 | } else if (T2->isInt() && T1->isFloat()) { 23 | return T1; 24 | } 25 | } else if (T1 && !T1->isUnknown()) { 26 | return T1; 27 | } else if (T2 && !T2->isUnknown()) { 28 | return T2; 29 | } 30 | return &UnknownType; 31 | } 32 | 33 | }} // namespace hue::ast 34 | -------------------------------------------------------------------------------- /src/ast/Type.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #ifndef HUE__AST_TYPE_DECLARATION_H 5 | #define HUE__AST_TYPE_DECLARATION_H 6 | #include "../Text.h" 7 | #include 8 | #include 9 | 10 | namespace hue { namespace ast { 11 | 12 | class ArrayType; 13 | 14 | // Declares a type, e.g. Float (double precision number) or [Int] (list of integer numbers) 15 | class Type { 16 | public: 17 | enum TypeID { 18 | Unknown = 0, 19 | Nil, // == i1 0 20 | Named, 21 | Float, 22 | Int, 23 | Char, 24 | Byte, 25 | Bool, 26 | Array, 27 | StructureT, 28 | FuncT, 29 | 30 | MaxTypeID 31 | }; 32 | 33 | Type(TypeID typeID) : typeID_(typeID) {} 34 | Type(const Text& name) : typeID_(Named), name_(name) {} 35 | Type(const Type& other) : typeID_(other.typeID_), name_(other.name_) {} 36 | virtual ~Type() {} 37 | 38 | inline const TypeID& typeID() const { return typeID_; } 39 | inline const Text& name() const { return name_; } 40 | 41 | bool isEqual(const Type& other) const { 42 | if (other.typeID() != typeID_) return false; 43 | return (typeID_ != Named || other.name() == name()); 44 | } 45 | 46 | inline bool isUnknown() const { return typeID_ == Unknown; } 47 | inline bool isFunction() const { return typeID_ == FuncT; } 48 | inline bool isInt() const { return typeID_ == Int; } 49 | inline bool isFloat() const { return typeID_ == Float; } 50 | inline bool isStructure() const { return typeID_ == StructureT; } 51 | 52 | virtual std::string toString() const { 53 | switch (typeID_) { 54 | case Unknown: return "?"; 55 | case Nil: return "Nil"; 56 | case Named: return name_.UTF8String(); 57 | case Float: return "Float"; 58 | case Int: return "Int"; 59 | case Char: return "Char"; 60 | case Byte: return "Byte"; 61 | case Bool: return "Bool"; 62 | case FuncT: return "func"; 63 | case StructureT: return "struct"; 64 | case Array: return "[?]"; 65 | default: return ""; 66 | } 67 | } 68 | 69 | virtual std::string toHueSource() const { return toString(); } 70 | 71 | virtual std::string canonicalName() const { return toString(); } 72 | 73 | static const Type* highestFidelity(const Type* T1, const Type* T2); 74 | 75 | private: 76 | TypeID typeID_; 77 | Text name_; 78 | }; 79 | 80 | extern const Type UnknownType; 81 | extern const Type NilType; 82 | extern const Type FloatType; 83 | extern const Type IntType; 84 | extern const Type CharType; 85 | extern const Type ByteType; 86 | extern const Type BoolType; 87 | 88 | 89 | class ArrayType : public Type { 90 | ArrayType(const Type* type) : Type(Array), type_(type) {} 91 | public: 92 | static const ArrayType* get(const Type* elementType) { 93 | // TODO: reuse 94 | return new ArrayType(elementType); 95 | } 96 | 97 | static const ArrayType* get(const Type& elementType) { 98 | // TODO: reuse 99 | return get(&elementType); 100 | } 101 | 102 | inline const Type* type() const { return type_; } 103 | 104 | virtual std::string toString() const { 105 | std::string s("["); 106 | s += (type_ ? type_->toString() : ""); 107 | s += "]"; 108 | return s; 109 | } 110 | 111 | virtual std::string canonicalName() const { 112 | std::string s("vector"); 113 | if (type_) 114 | s += '$' + type_->canonicalName(); 115 | return s; 116 | } 117 | 118 | private: 119 | const Type* type_; 120 | }; 121 | 122 | 123 | typedef std::vector TypeList; 124 | 125 | }} // namespace hue::ast 126 | #endif // HUE__AST_TYPE_DECLARATION_H 127 | -------------------------------------------------------------------------------- /src/ast/Variable.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #ifndef HUE__AST_VARIABLE_DEFINITION_H 5 | #define HUE__AST_VARIABLE_DEFINITION_H 6 | 7 | #include "Type.h" 8 | #include 9 | #include 10 | #include 11 | 12 | namespace hue { namespace ast { 13 | 14 | class Variable; 15 | typedef std::vector VariableList; 16 | 17 | class Variable { 18 | public: 19 | Variable(bool isMutable, const Text& name, const Type *type) 20 | : isMutable_(isMutable), name_(name), type_(type) {} 21 | 22 | // Primarily used for tests: 23 | Variable(const Type *type) : isMutable_(false), name_(), type_(type) {} 24 | 25 | const bool& isMutable() const { return isMutable_; } 26 | const Text& name() const { return name_; } 27 | 28 | const Type *type() const { return type_; } 29 | bool hasUnknownType() const { return !type_ || type_->isUnknown(); } 30 | void setType(const Type *type) { type_ = type; } 31 | 32 | std::string toString(int level = 0) const { 33 | std::ostringstream ss; 34 | ss << name_; 35 | if (isMutable_) 36 | ss << ""; 37 | if (!hasUnknownType()) 38 | ss << ':' << type_->toString(); 39 | return ss.str(); 40 | } 41 | 42 | private: 43 | bool isMutable_; 44 | Text name_; 45 | const Type *type_; 46 | }; 47 | 48 | 49 | 50 | 51 | }} // namespace hue::ast 52 | #endif // HUE__AST_VARIABLE_DEFINITION_H 53 | -------------------------------------------------------------------------------- /src/ast/ast.h: -------------------------------------------------------------------------------- 1 | #ifndef HUE_AST_AST_H 2 | #define HUE_AST_AST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #endif // HUE_AST_AST_H 19 | -------------------------------------------------------------------------------- /src/codegen/_VisitorImplFooter.h: -------------------------------------------------------------------------------- 1 | }} // namespace hue::codegen 2 | -------------------------------------------------------------------------------- /src/codegen/_VisitorImplHeader.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #include "../Logger.h" 5 | #include "Visitor.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace hue { namespace codegen { 21 | using namespace llvm; 22 | 23 | 24 | // String formatting helper. 25 | // std::string R_FMT(any << ..) 26 | // 27 | static std::ostringstream* __attribute__((unused)) _r_fmt_begin() { return new std::ostringstream; } 28 | static std::string __attribute__((unused)) _r_fmt_end(std::ostringstream* s) { 29 | std::string str = s->str(); 30 | delete s; 31 | return str; 32 | } 33 | #define R_FMT(A) _r_fmt_end( static_cast(&((*_r_fmt_begin()) << A )) ) 34 | 35 | static std::string __attribute__((unused)) llvmTypeToString(const llvm::Type& T) { 36 | std::string str; 37 | llvm::raw_string_ostream s(str); 38 | T.print(s); 39 | return s.str(); 40 | } 41 | static std::string __attribute__((unused)) llvmTypeToString(const llvm::Type const* T) { 42 | return llvmTypeToString(*T); 43 | } 44 | -------------------------------------------------------------------------------- /src/codegen/assignment.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #include 5 | 6 | #include "../Mangle.h" 7 | #include "_VisitorImplHeader.h" 8 | 9 | Value* Visitor::createNewLocalSymbol(const ast::Variable *variable, 10 | const ast::Type* hueType, 11 | Value *rhsValue, 12 | bool warnRedundantTypeDecl) 13 | { 14 | Type* rhsOriginalType = rhsValue->getType(); 15 | Value* V = rhsValue; 16 | const bool storageTypeIsKnown = variable->hasUnknownType() == false; 17 | Type *varT = 0; 18 | 19 | // Map Variable's type 20 | if (storageTypeIsKnown) { 21 | varT = IRTypeForASTType(hueType); 22 | if (varT == 0) return error("No encoding for variable's AST type"); 23 | } 24 | 25 | //bool requireAlloca = false; 26 | 27 | // If storage type is explicit/known --and-- RHS is a primitive: cast if needed 28 | if (storageTypeIsKnown && rhsOriginalType->isPrimitiveType()) { 29 | // If storage type is different than value, attempt to convert the value 30 | if (varT->getTypeID() != V->getType()->getTypeID()) { 31 | //requireAlloca = true; // Require an alloca since we are replacing V with a cast instr 32 | V = castValueTo(V, varT); 33 | if (V == 0) return error("Symbol/variable type is different than value type"); 34 | } 35 | } 36 | 37 | // Alloca+STORE if RHS is not a primitive --or-- the var is mutable 38 | if (V != rhsValue || variable->isMutable()) { 39 | rlog("Alloca+STORE variable \"" << variable->name() << "\""); 40 | V = createAllocaAndStoreValue(V, variable->name()); 41 | // Note: alloca optimization passes will take care of removing any unneeded 42 | // allocas that are the result of constant inlining. E.g. 43 | // x = 3.4 44 | // y = 3 45 | // z Int = y + x 46 | // 47 | // Would result in the following IR: 48 | // 49 | // %z = alloca i64 50 | // store i64 6, i64* %z 51 | // 52 | // Which, after an alloca optimization pass, will simply reference the constant i64 6: 53 | // 54 | // %z = i64 6 55 | // 56 | } else { 57 | Type* valueT = V->getType(); 58 | 59 | if (storageTypeIsKnown) { 60 | 61 | if (warnRedundantTypeDecl) { 62 | warning(std::string("Unneccessary type declaration of constant variable '") 63 | + variable->name().UTF8String() + "'"); 64 | } 65 | 66 | // Check types 67 | if (varT != valueT) { 68 | if (ArrayType::classof(varT) && ArrayType::classof(valueT)) { 69 | Type* varElementT = static_cast(varT)->getElementType(); 70 | Type* valueElementT = static_cast(valueT)->getElementType(); 71 | if (varElementT != valueElementT) { 72 | return error("Different types of arrays"); 73 | } 74 | // else: 75 | // Both are same kind of arrays, but of different size. Since we don't support type 76 | // definitions with fixes array size, this one is easy: valueT wins. We do nothing. 77 | } else { 78 | // Yikes. Type mis-match. This could be corrected by the programmer by having 79 | // the type being inferred instead of explicitly defined, since the var is constant. 80 | return error("Type mismatch between variable and value"); 81 | } 82 | } 83 | } 84 | 85 | // if (T->isPointerTy() && T->getNumContainedTypes() == 1 && T->getContainedType(0)->isFunctionTy()) { 86 | // rlog("is a pointer to a func"); 87 | // } 88 | } 89 | 90 | assert(hueType != 0); 91 | blockScope()->setSymbolTarget(variable->name(), hueType, V, variable->isMutable()); 92 | 93 | return V; 94 | } 95 | 96 | 97 | // Assignment 98 | Value *Visitor::codegenAssignment(const ast::Assignment* node) { 99 | DEBUG_TRACE_LLVM_VISITOR; 100 | 101 | // TODO: Make assignments that occur in the module block 102 | // global. That way we can also set their linkage to external 103 | // in order to have them exported, if marked for export. Use GlobalValue 104 | // for constant symbols and GlobalVariable for variable. 105 | 106 | // Get the variable 107 | const ast::Variable *variable = node->variable(); 108 | assert(variable != 0); 109 | 110 | // Codegen the RHS. 111 | Value *rhsValue; 112 | ast::FunctionType* hueFuncType = 0; 113 | 114 | if (node->rhs()->nodeTypeID() == ast::Node::TFunction) { 115 | ast::Function* funcNode = static_cast(node->rhs()); 116 | hueFuncType = funcNode->functionType(); 117 | 118 | if (hueFuncType->resultType() == 0 || !hueFuncType->resultType()->isUnknown()) { 119 | // Result type is known. 120 | 121 | // Generate a mangled name 122 | std::string mangledName = module_->getModuleIdentifier() + ":"; 123 | mangledName += variable->name().UTF8String(); 124 | mangledName += mangle(*funcNode->functionType()); 125 | 126 | // Has this function already been declared? (that is, same namespace, name, arg types and result types) 127 | if (moduleHasNamedGlobal(mangledName)) { 128 | return error("Implementation has already been defined for the symbol"); 129 | } 130 | 131 | // Generate function 132 | rhsValue = codegenFunction(funcNode, variable->name(), mangledName); 133 | 134 | } else { 135 | // Result type need to be inferred -- codegen function before we decide to keep it. 136 | std::string tempName = uniqueMangledName(variable->name()); 137 | rhsValue = codegenFunction(funcNode, variable->name(), tempName); 138 | Function* F = (Function*)rhsValue; 139 | if (F == 0) return 0; 140 | 141 | // Generate a mangled name 142 | std::string mangledName = module_->getModuleIdentifier() + ":"; 143 | mangledName += variable->name().UTF8String(); 144 | mangledName += mangle(F->getFunctionType()); 145 | 146 | // Has this function already been declared? (that is, same namespace, name, arg types and result types) 147 | if (moduleHasNamedGlobal(mangledName)) { 148 | F->eraseFromParent(); 149 | return error("Implementation has already been defined for the symbol"); 150 | } 151 | 152 | // Rename the function 153 | F->setName(mangledName); 154 | } 155 | 156 | } else if (node->rhs()->nodeTypeID() == ast::Node::TExternalFunction) { 157 | const ast::ExternalFunction* externalFuncNode = static_cast(node->rhs()); 158 | hueFuncType = externalFuncNode->functionType(); 159 | rhsValue = codegenExternalFunction(externalFuncNode); 160 | 161 | } else if (node->rhs()->nodeTypeID() == ast::Node::TCall) { 162 | // Create type list from LHS variable, which the call codegen can use in the case 163 | // where there are multiple function candidates that only differ on return type. 164 | rhsValue = codegenCall(static_cast(node->rhs()), variable->type()); 165 | 166 | } else if (node->rhs()->isStructure()) { 167 | const ast::Structure* st = static_cast(node->rhs()); 168 | 169 | // Generate a mangled name 170 | std::string mangledName = module_->getModuleIdentifier() + ":"; 171 | mangledName += variable->name().UTF8String(); 172 | mangledName += mangle(*st->resultStructType()); 173 | 174 | rhsValue = codegenStructure(st, mangledName); 175 | 176 | } else { 177 | rhsValue = codegen(node->rhs()); 178 | } 179 | if (rhsValue == 0) return 0; 180 | 181 | 182 | 183 | // Functions are treated differently 184 | FunctionType* FT = functionTypeForValue(rhsValue); 185 | if (FT) { 186 | assert(hueFuncType != 0); 187 | if (blockScope()->setFunctionSymbolTarget(variable->name(), hueFuncType, FT, rhsValue) == false) { 188 | return error("Implementation has already been defined for the symbol"); 189 | } 190 | 191 | } else { 192 | // We are dealing with something not a function 193 | 194 | // Look up the name in this direct scope. 195 | const SymbolTarget& symbol = blockScope()->lookupSymbolTarget(variable->name()); 196 | Value *existingValue = symbol.value; 197 | 198 | // Check if there's a function symbol with the same name 199 | if (existingValue == 0) { 200 | if (blockScope()->lookupFunctionSymbolTargets(variable->name()) != 0) { 201 | return error("Symbol has already been defined"); 202 | } 203 | } 204 | 205 | if (existingValue == 0) { 206 | // New symbol 207 | bool warnRedundantTypeDecl = (node->rhs()->nodeTypeID() != ast::Node::TCall); 208 | rhsValue = createNewLocalSymbol(variable, node->rhs()->resultType(), 209 | rhsValue, warnRedundantTypeDecl); 210 | if (rhsValue == 0) return 0; 211 | 212 | } else { 213 | // Existing symbol 214 | if (symbol.isMutable) { 215 | if (!AllocaInst::classof(existingValue)) { 216 | return error("not implemented: promote mutatable ref to alloca"); 217 | } else { 218 | // STORE the value 219 | llvm::StoreInst* si = builder_.CreateStore(rhsValue, static_cast(existingValue)); 220 | rhsValue = si; 221 | } 222 | } else { 223 | rlog(variable->name() << " is not mutable"); 224 | return error("Symbol has already been defined"); 225 | } 226 | } 227 | 228 | } 229 | 230 | return rhsValue; 231 | } 232 | 233 | #include "_VisitorImplFooter.h" 234 | -------------------------------------------------------------------------------- /src/codegen/binop.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #include "_VisitorImplHeader.h" 5 | 6 | Value *Visitor::codegenBinaryOp(const ast::BinaryOp *binOpExp) { 7 | DEBUG_TRACE_LLVM_VISITOR; 8 | 9 | ast::Expression *lhs = binOpExp->lhs(); 10 | ast::Expression *rhs = binOpExp->rhs(); 11 | 12 | Value *L = codegen(lhs); if (L == 0) return 0; 13 | Value *R = codegen(rhs); if (R == 0) return 0; 14 | 15 | Type* LT = L->getType(); 16 | Type* RT = R->getType(); 17 | Type* type = LT; 18 | 19 | // Numbers: cast to richest type if needed 20 | if (LT->isIntegerTy() && RT->isDoubleTy()) { 21 | // Cast L to double 22 | //rlog("Binop: Cast LHS to double"); 23 | L = builder_.CreateSIToFP(L, (type = RT), "itoftmp"); 24 | } else if (LT->isDoubleTy() && RT->isIntegerTy()) { 25 | // Cast R to double 26 | //rlog("Binop: Cast RHS to double. LHS -> "); L->dump(); 27 | R = builder_.CreateSIToFP(R, (type = LT), "itoftmp"); 28 | } 29 | 30 | // std::cerr << "L: "; if (!L) std::cerr << "" << std::endl; else L->dump(); 31 | // std::cerr << "R: "; if (!R) std::cerr << "" << std::endl; else R->dump(); 32 | // 33 | // LT = L->getType(); 34 | // RT = R->getType(); 35 | // std::cerr << "LT: "; if (!LT) std::cerr << "" << std::endl; else { 36 | // LT->dump(); std::cerr << std::endl; } 37 | // std::cerr << "RT: "; if (!RT) std::cerr << "" << std::endl; else { 38 | // RT->dump(); std::cerr << std::endl; } 39 | 40 | switch (binOpExp->operatorValue()) { 41 | 42 | case '+': { 43 | if (type->isIntegerTy()) { 44 | return builder_.CreateAdd(L, R, "addtmp"); 45 | } else if (type->isDoubleTy()) { 46 | return builder_.CreateFAdd(L, R, "addtmp"); 47 | } else { 48 | return error(R_FMT("Invalid operand type for binary operator \"" << binOpExp->operatorName() << "\"" )); 49 | } 50 | } 51 | 52 | case '-': { 53 | if (type->isIntegerTy()) { 54 | return builder_.CreateSub(L, R, "subtmp"); 55 | } else if (type->isDoubleTy()) { 56 | return builder_.CreateFSub(L, R, "subtmp"); 57 | } else { 58 | break; 59 | } 60 | } 61 | 62 | case '*': { 63 | if (type->isIntegerTy()) { 64 | return builder_.CreateMul(L, R, "multmp"); 65 | } else if (type->isDoubleTy()) { 66 | return builder_.CreateFMul(L, R, "multmp"); 67 | } else { 68 | break; 69 | } 70 | } 71 | 72 | case '/': { 73 | // UDiv: unsigned integer division 74 | // SDiv: signed integer division 75 | // FDiv: floating point division 76 | if (type->isIntegerTy()) { 77 | return builder_.CreateSDiv(L, R, "divtmp"); 78 | } else if (type->isDoubleTy()) { 79 | return builder_.CreateFDiv(L, R, "divtmp"); 80 | } else { 81 | break; 82 | } 83 | } 84 | 85 | case '<': { 86 | // '<=' 87 | if (binOpExp->isEqualityLTRKind()) { 88 | if (type->isIntegerTy()) { 89 | return builder_.CreateICmpSLE(L, R, "letmp"); // -> Int 0|1 90 | } else if (type->isDoubleTy()) { 91 | // FCMP_OGE -- True if LHS is ordered (not NAN) and less than or equal to RHS 92 | // 93 | // (3.1 <= 3.4) -> 1 94 | // (3.4 <= 3.4) -> 1 95 | // (8.0 <= 3.4) -> 0 96 | // (NAN <= 3.4) -> 0 97 | // (NAN <= NAN) -> 0 98 | // (9.0 <= NAN) -> 0 99 | // 100 | return builder_.CreateFCmpOLE(L, R, "letmp"); // -> Int 0|1 101 | } 102 | 103 | // '<' 104 | } else { 105 | if (type->isIntegerTy()) { 106 | return builder_.CreateICmpSLT(L, R, "lttmp"); // -> Int 0|1 107 | } else if (type->isDoubleTy()) { 108 | // True if LHS is ordered (not NAN) and less than RHS 109 | // 110 | // (3.1 < 3.4) -> 1 111 | // (3.4 < 3.4) -> 0 112 | // (8.0 < 3.4) -> 1 113 | // (NAN < 3.4) -> 0 114 | // (NAN < NAN) -> 0 115 | // (9.0 < NAN) -> 0 116 | // 117 | return builder_.CreateFCmpOLT(L, R, "lttmp"); // -> Int 0|1 118 | } 119 | } 120 | return error(R_FMT("Invalid operand type for binary operator \"" << binOpExp->operatorName() << "\"" )); 121 | } 122 | 123 | case '>': { 124 | // '>=' 125 | if (binOpExp->isEqualityLTRKind()) { 126 | if (type->isIntegerTy()) { 127 | return builder_.CreateICmpSGE(L, R, "getmp"); // -> Int 0|1 128 | } else if (type->isDoubleTy()) { 129 | // FCMP_OGE -- True if LHS is ordered (not NAN) and greater than or equal to RHS 130 | // 131 | // (3.1 >= 3.4) -> 0 132 | // (3.4 >= 3.4) -> 1 133 | // (8.0 >= 3.4) -> 1 134 | // (NAN >= 3.4) -> 0 135 | // (NAN >= NAN) -> 0 136 | // (9.0 >= NAN) -> 0 137 | // 138 | return builder_.CreateFCmpOGE(L, R, "getmp"); // -> Int 0|1 139 | } 140 | 141 | // '>' 142 | } else { 143 | if (type->isIntegerTy()) { 144 | return builder_.CreateICmpSGT(L, R, "gttmp"); // -> Int 0|1 145 | } else if (type->isDoubleTy()) { 146 | // FCMP_OGT -- True if LHS is ordered (not NAN) AND greater than RHS 147 | // 148 | // (3.1 > 3.4) -> 0 149 | // (3.4 > 3.4) -> 0 150 | // (8.0 > 3.4) -> 1 151 | // (NAN > 3.4) -> 0 152 | // (NAN > NAN) -> 0 153 | // (9.0 > NAN) -> 0 154 | // 155 | return builder_.CreateFCmpOGT(L, R, "gttmp"); // -> Int 0|1 156 | } 157 | } 158 | return error(R_FMT("Invalid operand type for binary operator \"" << binOpExp->operatorName() << "\"" )); 159 | } 160 | 161 | case '!': { 162 | // '!=' 163 | if (binOpExp->isEqualityLTRKind()) { 164 | if (type->isIntegerTy()) { 165 | return builder_.CreateICmpNE(L, R, "netmp"); // -> Int 0|1 166 | } else if (type->isDoubleTy()) { 167 | // We use UNE, since the ONE behavior ((NAN != 3.4) -> False) is a weirder than 168 | // ((NAN != NAN) -> True). 169 | // 170 | // FCMP_UNE -- True if (LHS is?) unordered (NAN) OR operands are unequal 171 | // 172 | // (3.1 != 3.4) -> 1 173 | // (3.4 != 3.4) -> 0 174 | // (NAN != 3.4) -> 1 175 | // (NAN != NAN) -> 1 176 | // (3.0 != 3.4) -> 0 177 | // 178 | return builder_.CreateFCmpUNE(L, R, "netmp"); // -> Int 0|1 179 | } 180 | return error(R_FMT("Invalid operand type for binary operator \"" << binOpExp->operatorName() << "\"" )); 181 | } 182 | // Note: There's no "else" since there's no '!' infix operator 183 | break; 184 | } 185 | 186 | case '=': { 187 | // '==' 188 | if (binOpExp->isEqualityLTRKind()) { 189 | if (type->isIntegerTy()) { 190 | return builder_.CreateICmpEQ(L, R, "eqtmp"); // -> Int 0|1 191 | } else if (type->isDoubleTy()) { 192 | // True if (LHS is?) ordered (not NAN) and equal 193 | // 194 | // FCMP_OEQ (==) FCMP_UNE (!=) 195 | // (3.1 == 3.4) -> 0 (3.1 != 3.4) -> 1 196 | // (3.4 == 3.4) -> 1 (3.4 != 3.4) -> 0 197 | // (NAN == 3.4) -> 0 (NAN != 3.4) -> 1 198 | // (NAN == NAN) -> 0 (NAN != NAN) -> 1 199 | // (3.0 == 3.4) -> 1 (3.0 != 3.4) -> 0 200 | // 201 | return builder_.CreateFCmpOEQ(L, R, "eqtmp"); // -> Int 0|1 202 | } 203 | return error(R_FMT("Invalid operand type for binary operator \"" << binOpExp->operatorName() << "\"" )); 204 | } 205 | // Note: There's no "else" since '=' should never exist as a binop, as it 206 | // has a special class ast::Assignment. 207 | break; 208 | } 209 | 210 | default: break; 211 | } 212 | 213 | return error(R_FMT("Invalid binary operator \"" << binOpExp->operatorName() << "\"" )); 214 | } 215 | 216 | #include "_VisitorImplFooter.h" 217 | -------------------------------------------------------------------------------- /src/codegen/call.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #include "_VisitorImplHeader.h" 5 | 6 | // Returns true if V can be used as the target in a call instruction 7 | inline static bool valueIsCallable(Value* V) { 8 | return !!Visitor::functionTypeForValue(V); 9 | } 10 | 11 | std::string Visitor::formatFunctionCandidateErrorMessage(const ast::Call* node, 12 | const FunctionSymbolTargetList& candidateFuncs, 13 | CandidateError error) const 14 | { 15 | std::string utf8calleeName = node->symbol()->toString(); 16 | std::ostringstream ss; 17 | 18 | if (error == CandidateErrorArgCount) { 19 | ss << "No function matching call to "; 20 | } else if (error == CandidateErrorArgTypes) { 21 | ss << "No function with arguments matching call to "; 22 | } else if (error == CandidateErrorReturnType) { 23 | ss << "No function with result matching call to "; 24 | } else if (error == CandidateErrorAmbiguous) { 25 | ss << "Ambiguous function call to "; 26 | } else { 27 | ss << "No viable function for call to "; 28 | } 29 | 30 | // TODO: Proper toHueSource() repr here: 31 | ss << utf8calleeName << "/" << node->arguments().size() << ". "; 32 | 33 | if (error == CandidateErrorArgCount) { 34 | ss << "Did you mean to call any of these functions?"; 35 | } else if (error == CandidateErrorReturnType) { 36 | ss << "Express what type of result you expect. Available functions:"; 37 | } else { 38 | ss << "Candidates are:"; 39 | } 40 | 41 | ss << std::endl; 42 | FunctionSymbolTargetList::const_iterator it2 = candidateFuncs.begin(); 43 | for (; it2 != candidateFuncs.end(); ++it2) { 44 | ss << " " << utf8calleeName << ' ' << (*it2).hueType->toHueSource() << std::endl; 45 | } 46 | 47 | return ss.str(); 48 | } 49 | 50 | 51 | Value *Visitor::codegenCall(const ast::Call* node, const ast::Type* expectedReturnType/* = 0*/) { 52 | DEBUG_TRACE_LLVM_VISITOR; 53 | const ast::Symbol& symbol = *node->symbol(); 54 | 55 | // TODO FIXME: This will fail for lookups into any structs (e.g. foo:bar) since 56 | // we have not implemented struct traversal for symbol lookup, in the 57 | // special function symbol table. 58 | if (symbol.isPath()) { 59 | return error(std::string("Not implemented: Struct traversal for function symbols (at symbol \"") 60 | + symbol.toString() + "\")"); 61 | } 62 | 63 | // Look up a list of matching function symbols 64 | FunctionSymbolTargetList candidateFuncs = lookupFunctionSymbols(symbol); 65 | 66 | // No symbol? 67 | if (candidateFuncs.empty()) { 68 | // TODO: We could take all known symbols, order them by edit distance and suggest 69 | // the top N (N is perhaps controlled by a quality threshold) symbol names. 70 | return error(std::string("Unknown symbol \"") + node->symbol()->toString() + "\""); 71 | } 72 | 73 | // Local ref to input arguments, for our convenience. 74 | const ast::Call::ArgumentList& arguments = node->arguments(); 75 | 76 | // Filter out functions that take a different number of arguments 77 | FunctionSymbolTargetList::const_iterator it = candidateFuncs.begin(); 78 | FunctionSymbolTargetList candidateFuncsMatchingArgCount; 79 | for (; it != candidateFuncs.end(); ++it) { 80 | if (static_cast((*it).type->getNumParams()) == arguments.size()) 81 | candidateFuncsMatchingArgCount.push_back(*it); 82 | } 83 | 84 | // No candidates with the same number of arguments? 85 | if (candidateFuncsMatchingArgCount.empty()) { 86 | return error(formatFunctionCandidateErrorMessage(node, candidateFuncs, CandidateErrorArgCount)); 87 | } 88 | // TODO: If candidateFuncs.size() == 1 here, we can take some shortcuts, perhaps. 89 | 90 | // Now, we pause the function candidate selection for a little while and 91 | // visit the arguments. We need to do this in order to know the types of 92 | // the arguments. The types need to be resolved in order for us to be able 93 | // to find a matching function candidate. 94 | 95 | // Build argument list by codegen'ing all input variables 96 | std::vector argValues; 97 | ast::Call::ArgumentList::const_iterator inIt = arguments.begin(); 98 | for (; inIt != arguments.end(); ++inIt) { 99 | // Codegen the input value and store it 100 | Value* inputV = codegen(*inIt); 101 | if (inputV == 0) return 0; 102 | argValues.push_back(inputV); 103 | } 104 | 105 | // Find a function that matches the arguments 106 | FunctionSymbolTargetList::const_iterator it2 = candidateFuncsMatchingArgCount.begin(); 107 | FunctionSymbolTargetList candidateFuncsMatchingTypes; 108 | for (; it2 != candidateFuncsMatchingArgCount.end(); ++it2) { 109 | FunctionType* candidateFT = (*it2).type; 110 | size_t i = 0; 111 | FunctionType::param_iterator ftPT = candidateFT->param_begin(); 112 | bool allTypesMatch = true; 113 | assert(argValues.size() == candidateFT->getNumParams()); 114 | 115 | // Check each argument type 116 | for (; ftPT != candidateFT->param_end(); ++ftPT, ++i) { 117 | Type* argT = argValues[i]->getType(); 118 | Type* expectT = *ftPT; 119 | 120 | // Unless the types are equal, remove the candidate function from the list and 121 | // stop checking types. 122 | if (argT != expectT) { // a better cmp, e.g. "isCompatible" 123 | allTypesMatch = false; 124 | break; 125 | } 126 | } 127 | 128 | // If all argument types matched, this is a viable candidate 129 | if (allTypesMatch) 130 | candidateFuncsMatchingTypes.push_back(*it2); 131 | } 132 | 133 | // No candidates? 134 | if (candidateFuncsMatchingTypes.empty()) { 135 | return error(formatFunctionCandidateErrorMessage(node, candidateFuncsMatchingArgCount, 136 | CandidateErrorArgTypes)); 137 | } 138 | 139 | 140 | // We will later store the selected candidate here 141 | Value* targetV = 0; 142 | FunctionType* targetFT = 0; 143 | 144 | 145 | // If we have some expected return types, try to use that information to narrow down our 146 | // list of candidates. 147 | if (expectedReturnType != 0) { 148 | 149 | // Reduce our list of candidates according to expected return types 150 | FunctionSymbolTargetList candidateFuncsMatchingReturns; 151 | FunctionSymbolTargetList::const_iterator it3 = candidateFuncsMatchingTypes.begin(); 152 | for (; it3 != candidateFuncsMatchingTypes.end(); ++it3) { 153 | 154 | // Get the list types that the candidate returns 155 | const ast::Type* candidateReturnType = (*it3).hueType->resultType(); 156 | 157 | // Number of results must match, or we ignore this candidate 158 | if (!expectedReturnType->isEqual(*candidateReturnType)) { 159 | continue; // ignore candidate 160 | } 161 | 162 | if (expectedReturnType == 0) { 163 | // Expects no result and candidate does not return anything 164 | if (candidateReturnType == 0) { 165 | candidateFuncsMatchingReturns.push_back(*it3); 166 | } 167 | } else if ( expectedReturnType->typeID() == ast::Type::Unknown 168 | && candidateFuncsMatchingTypes.size() == 1) { 169 | // Expected type should be inferred and we have only a single candidate. 170 | // This means that we chose this candidate and whatever whats its type inferred will 171 | // do so based on whatever this candidate returns. 172 | candidateFuncsMatchingReturns.push_back(*it3); 173 | 174 | } else if (candidateReturnType->isEqual(*expectedReturnType)) { 175 | // The return types are equal. 176 | candidateFuncsMatchingReturns.push_back(*it3); 177 | } 178 | 179 | } 180 | 181 | // Did we find a single candidate? 182 | if (candidateFuncsMatchingReturns.size() == 1) { 183 | targetV = candidateFuncsMatchingReturns[0].value; 184 | targetFT = candidateFuncsMatchingReturns[0].type; 185 | } else if (candidateFuncsMatchingReturns.size() == 0) { 186 | return error(formatFunctionCandidateErrorMessage(node, candidateFuncsMatchingTypes, 187 | CandidateErrorReturnType)); 188 | } else { 189 | return error(formatFunctionCandidateErrorMessage(node, candidateFuncsMatchingTypes, 190 | CandidateErrorAmbiguous)); 191 | } 192 | 193 | } else { 194 | // We don't have any hints about expected return values to go on. 195 | // If the have a single candidate, let's use that. Otherwise it's an error. 196 | if (candidateFuncsMatchingTypes.size() == 1) { 197 | targetV = candidateFuncsMatchingTypes[0].value; 198 | targetFT = candidateFuncsMatchingTypes[0].type; 199 | } else { 200 | return error(formatFunctionCandidateErrorMessage(node, candidateFuncsMatchingTypes, 201 | CandidateErrorAmbiguous)); 202 | } 203 | } 204 | 205 | // Create call instruction 206 | if (targetFT->getReturnType()->isVoidTy()) { 207 | builder_.CreateCall(targetV, argValues); 208 | return ConstantInt::getFalse(getGlobalContext()); 209 | } else { 210 | return builder_.CreateCall(targetV, argValues, node->symbol()->toString() + "_res"); 211 | } 212 | } 213 | 214 | #include "_VisitorImplFooter.h" 215 | -------------------------------------------------------------------------------- /src/codegen/conditional.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "_VisitorImplHeader.h" 4 | 5 | Value* Visitor::codegenConditional(const ast::Conditional *cond) { 6 | DEBUG_TRACE_LLVM_VISITOR; 7 | 8 | // Verify the conditional 9 | if (cond->testExpression() == 0) return error("Missing test expression in conditional"); 10 | if (cond->trueBlock() == 0) return error("Missing true block in conditional"); 11 | if (cond->falseBlock() == 0) return error("Missing false block in conditional"); 12 | 13 | // Get enclosing function 14 | Function *F = builder_.GetInsertBlock()->getParent(); 15 | 16 | // Codegen test expression 17 | Value* testV = codegen(cond->testExpression()); 18 | if (testV == 0) return 0; 19 | 20 | // Cast test expression result to boolean if needed 21 | if (!testV->getType()->isIntegerTy(1)) { 22 | testV = castValueToBool(testV); 23 | if (testV == 0) return 0; 24 | } 25 | 26 | // Conditional result type 27 | Type* resultT = IRTypeForASTType(cond->resultType()); 28 | if (resultT == 0) return 0; 29 | 30 | // True, false and end block 31 | BasicBlock *trueBB = BasicBlock::Create(getGlobalContext(), "then"); 32 | BasicBlock *falseBB = BasicBlock::Create(getGlobalContext(), "else"); 33 | BasicBlock *endBB = BasicBlock::Create(getGlobalContext(), "endif"); 34 | 35 | // Conditional branch instruction. If testV is true, continue execution at trueBB. 36 | // Otherwise continue execution at falseBB. 37 | builder_.CreateCondBr(testV, trueBB, falseBB); 38 | 39 | // ------ 40 | // Put the true block at the end of the current function and set it as insertion 41 | F->getBasicBlockList().push_back(trueBB); 42 | builder_.SetInsertPoint(trueBB); 43 | 44 | // Codegen the true block 45 | Value *trueV = codegenBlock(cond->trueBlock()); 46 | if (trueV == 0) return 0; 47 | 48 | // Check result type and appempt cast if needed 49 | if (trueV->getType() != resultT) { 50 | trueV = castValueTo(trueV, resultT); 51 | if (trueV == 0) return 0; 52 | } 53 | 54 | // Terminate the true block with a "jump" to the "endif" block 55 | builder_.CreateBr(endBB); 56 | 57 | // Codegen of true block can change the current block, update trueBB for the PHI. 58 | trueBB = builder_.GetInsertBlock(); 59 | 60 | 61 | // ------ 62 | // Put the false block at the end of the current function and set it as insertion 63 | F->getBasicBlockList().push_back(falseBB); 64 | builder_.SetInsertPoint(falseBB); 65 | 66 | // Codegen the false block 67 | Value *falseV = codegenBlock(cond->falseBlock()); 68 | if (falseV == 0) return 0; 69 | 70 | // Check result type and appempt cast if needed 71 | if (falseV->getType() != resultT) { 72 | falseV = castValueTo(falseV, resultT); 73 | if (falseV == 0) return 0; 74 | } 75 | 76 | // Terminate the false block with a "jump" to the "endif" block 77 | builder_.CreateBr(endBB); 78 | 79 | // Codegen of false block can change the current block, update trueBB for the PHI. 80 | falseBB = builder_.GetInsertBlock(); 81 | 82 | // ------ 83 | // Create endif block 84 | F->getBasicBlockList().push_back(endBB); 85 | builder_.SetInsertPoint(endBB); 86 | 87 | // Add PHI to the endif block 88 | PHINode *phi = builder_.CreatePHI(resultT, 2, "ifres"); 89 | phi->addIncoming(trueV, trueBB); 90 | phi->addIncoming(falseV, falseBB); 91 | 92 | // Return the PHI 93 | return phi; 94 | } 95 | 96 | #include "_VisitorImplFooter.h" 97 | -------------------------------------------------------------------------------- /src/codegen/data_literal.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "_VisitorImplHeader.h" 4 | 5 | 6 | Value *Visitor::codegenDataLiteral(const ast::DataLiteral *dataLit) { 7 | DEBUG_TRACE_LLVM_VISITOR; 8 | 9 | //return wrap(ConstantArray::get(*unwrap(C), StringRef(Str, Length), DontNullTerminate == 0)); 10 | //bool AddNull = false; 11 | //ConstantArray::get(getGlobalContext(), StringRef(Str, Length), AddNull); 12 | // ByteString::const_iterator it = dataLit->data().begin(); 13 | // ByteString::const_iterator it_end = dataLit->data().end(); 14 | // size_t i = 0, count = dataLit->data().size(); 15 | // std::vector elems; 16 | // elems.reserve(count); 17 | // 18 | // for (; it != it_end; ++it, ++i) { 19 | // elems.push_back( ConstantInt::get(getGlobalContext(), APInt(8, *it, false)) ); 20 | // } 21 | //ArrayType::get(Type::FloatTy, 4); 22 | //ArrayRef V = makeArrayRef(elems); 23 | 24 | // Create constant array with the actual bytes 25 | const bool addNull = false; 26 | Constant* arrayV = ConstantArray::get(getGlobalContext(), 27 | StringRef(reinterpret_cast(dataLit->data().data()), dataLit->data().size()), 28 | addNull); 29 | 30 | GlobalVariable* arrayGV = createArray(arrayV, "data"); 31 | 32 | Type* T = PointerType::get(getArrayStructType(builder_.getInt8Ty()), 0); 33 | return builder_.CreatePointerCast(arrayGV, T); 34 | 35 | // wrapConstantArrayValueInGEP: 36 | // Value *zero = ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0); 37 | // Value *Args[] = { zero, zero }; 38 | // //Value* V = builder_.CreateInBoundsGEP(gV, Args, "dataptr"); 39 | // Value* V = builder_.CreateGEP(gV, Args, "dataptr"); 40 | } 41 | 42 | #include "_VisitorImplFooter.h" 43 | -------------------------------------------------------------------------------- /src/codegen/function_type.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "_VisitorImplHeader.h" 4 | 5 | 6 | 7 | Function *Visitor::codegenFunctionType(ast::FunctionType *astFT, 8 | std::string name, // = "", 9 | Type *returnType // = 0 10 | ) { 11 | DEBUG_TRACE_LLVM_VISITOR; 12 | 13 | // No return type means void 14 | if (returnType == 0) { 15 | returnType = builder_.getVoidTy(); 16 | } 17 | 18 | // Get LLVM function type 19 | FunctionType *FT = getLLVMFuncTypeForASTFuncType(astFT, returnType); 20 | if (FT == 0) return 0; 21 | 22 | if (!FT) return (Function*)error("Failed to create function type"); 23 | 24 | // Create function 25 | GlobalValue::LinkageTypes linkageType = GlobalValue::PrivateLinkage; 26 | if (astFT->isPublic()) { 27 | linkageType = GlobalValue::ExternalLinkage; 28 | } 29 | Function *F = Function::Create(FT, linkageType, name, module_); 30 | if (!F) return (Function*)error("Failed to create function"); 31 | 32 | // No unwinding 33 | F->setDoesNotThrow(); 34 | 35 | ast::VariableList *argVars = astFT->args(); 36 | 37 | // If F conflicted, there was already something named 'Name'. If it has a 38 | // body, don't allow redefinition or reextern. 39 | if (F->getName() != name) { 40 | // Delete the one we just made and get the existing one. 41 | F->eraseFromParent(); 42 | F = module_->getFunction(name); 43 | 44 | // If F already has a body, reject this. 45 | if (!F->empty()) { 46 | return (Function*)error("redefinition of a concrete function"); 47 | return 0; 48 | } 49 | 50 | // If F took a different number of args, reject. 51 | if ( (argVars == 0 && F->arg_size() != 0) || (argVars != 0 && F->arg_size() != argVars->size()) ) { 52 | return (Function*)error("redefinition of a function with different arguments"); 53 | } 54 | } 55 | 56 | // Set names for all arguments. 57 | if (argVars) { 58 | unsigned i = 0; 59 | for (Function::arg_iterator AI = F->arg_begin(); i != argVars->size(); ++AI, ++i) { 60 | const Text& argName = (*argVars)[i]->name(); 61 | AI->setName(argName.UTF8String()); 62 | } 63 | } 64 | 65 | return F; 66 | } 67 | 68 | #include "_VisitorImplFooter.h" 69 | -------------------------------------------------------------------------------- /src/codegen/structure.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "_VisitorImplHeader.h" 4 | 5 | 6 | Value* Visitor::codegenConstantStructure(StructType *ST, const std::vector& fields, const Text& name) { 7 | Constant* V = ConstantStruct::get(ST, fields); 8 | 9 | std::string irname; 10 | GlobalValue::LinkageTypes linkage; 11 | 12 | if (name.empty()) { 13 | irname = "struct"; 14 | linkage = GlobalValue::InternalLinkage; 15 | } else { 16 | irname = name.UTF8String(); 17 | linkage = GlobalValue::ExternalLinkage; 18 | 19 | // Expose as global var 20 | V = new GlobalVariable(*module_, ST, 21 | /*isConstant=*/ true, 22 | /*Linkage=*/ linkage, 23 | /*Initializer=*/ V, 24 | /*Name=*/ irname); 25 | //GV->setAlignment(4); 26 | } 27 | 28 | Type* PT = PointerType::get(ST, 0); 29 | return builder_.CreatePointerCast(V, PT); 30 | } 31 | 32 | 33 | Value* Visitor::codegenDynamicStructure(StructType *ST, const std::vector& values, const Text& name) { 34 | DEBUG_TRACE_LLVM_VISITOR; 35 | AllocaInst* allocaV = builder_.CreateAlloca(ST, 0, name.UTF8String()); 36 | //Value* V = builder_.CreateLoad(allocaV); 37 | 38 | for (unsigned i = 0, L = values.size(); i != L; ++i) { 39 | Value *elementV = builder_.CreateStructGEP(allocaV, i); 40 | builder_.CreateStore(values[i], elementV); 41 | } 42 | 43 | return allocaV; 44 | } 45 | 46 | 47 | Value* Visitor::codegenStructure(const ast::Structure *structure, const Text& name) { 48 | DEBUG_TRACE_LLVM_VISITOR; 49 | 50 | const ast::StructType* astST = static_cast(structure->resultType()); 51 | 52 | std::vector fields; 53 | std::vector constFields; 54 | const ast::ExpressionList& expressions = structure->block()->expressions(); 55 | bool initializerIsConstant = true; 56 | 57 | for (ast::ExpressionList::const_iterator I = expressions.begin(), E = expressions.end(); I != E; ++I) { 58 | ast::Expression* expr = *I; 59 | Value* V = codegen(expr); 60 | if (V == 0) return 0; // todo cleanup 61 | 62 | if (initializerIsConstant) { 63 | if (Constant::classof(V)) { 64 | constFields.push_back(static_cast(V)); 65 | } else { 66 | initializerIsConstant = false; 67 | } 68 | } 69 | 70 | fields.push_back(V); 71 | } 72 | 73 | StructType *ST = getExplicitStructType(astST); 74 | if (ST == 0) return 0; 75 | 76 | if (initializerIsConstant) { 77 | return codegenConstantStructure(ST, constFields, name); 78 | } else { 79 | return codegenDynamicStructure(ST, fields, name); 80 | } 81 | } 82 | 83 | #include "_VisitorImplFooter.h" 84 | -------------------------------------------------------------------------------- /src/codegen/symbol.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "_VisitorImplHeader.h" 4 | 5 | Value *Visitor::codegenSymbol(const ast::Symbol *symbol) { 6 | DEBUG_TRACE_LLVM_VISITOR; 7 | assert(symbol != 0); 8 | 9 | // Get and check pathname 10 | const Text::List& pathname = symbol->pathname(); 11 | if (pathname.size() == 0) 12 | return error((std::string("Unknown symbol \"") + symbol->toString() + "\"")); 13 | 14 | // Lookup symbol 15 | const SymbolTarget& target = lookupSymbol(pathname[0]); 16 | if (target.empty()) 17 | return error((std::string("Unknown symbol \"") + symbol->toString() + "\"")); 18 | 19 | // Extract the targets value 20 | Value* V = target.value; 21 | 22 | // Deep? 23 | if (pathname.size() > 1) { 24 | const ast::Type* hueType = target.hueType; 25 | assert(hueType != 0); 26 | //ArrayRef gepPath 27 | //size_t gepIndex = 0; 28 | //size_t gepIndexCount = pathname.size(); 29 | //Value* GEPPath[gepIndexCount * 2]; 30 | //Value* i32_0V = builder_.getInt32(0); 31 | 32 | for (Text::List::const_iterator I = pathname.begin()+1, E = pathname.end(); I != E; ++I) { 33 | //rlog("Digging into " << hueType->toString()); 34 | const Text& name = *I; 35 | 36 | // Verify that the target is a struct 37 | if (!hueType->isStructure()) { 38 | return error((std::string("Base of symbol \"") + symbol->toString() 39 | + "\" does not refer to a structure")); 40 | } 41 | const ast::StructType* hueST = static_cast(hueType); 42 | 43 | // Find member offset 44 | size_t memberIndex = hueST->indexOf(name); 45 | if (memberIndex == SIZE_MAX) { 46 | return error(std::string("Unknown symbol \"") + name.UTF8String() 47 | + "\" in structure " + hueST->toString() ); 48 | } 49 | 50 | // Type for name 51 | hueType = (*hueST)[name]; 52 | assert(hueType != 0); 53 | assert(V->getType()->isPointerTy()); // V should be a pointer 54 | assert(V->getType()->getNumContainedTypes() == 1); // V should reference exactly one item 55 | assert(V->getType()->getContainedType(0)->isStructTy()); // V[0] should be a struct 56 | 57 | //rlog("V entry: " << llvmTypeToString(V->getType())); V->dump(); 58 | 59 | // Get element pointer 60 | V = builder_.CreateStructGEP(V, memberIndex, name.UTF8String()); 61 | 62 | // Struct member is a pointer to something 63 | assert(V->getType()->isPointerTy() && V->getType()->getNumContainedTypes() == 1); 64 | 65 | // Load the member 66 | V = builder_.CreateLoad(V, "loadsm"); 67 | } 68 | 69 | return V; 70 | } 71 | 72 | // Value must be either a global or in the same scope 73 | assert(blockScope() != 0); 74 | if (target.owningScope != blockScope()) { 75 | if (!GlobalValue::classof(target.value)) { 76 | // TODO: Future: If we support funcs that capture its environment, that code should 77 | // likely live here. 78 | return error((std::string("Unknown symbol \"") + symbol->toString() + "\" (no reachable symbols in scope)").c_str()); 79 | } 80 | #if DEBUG_LLVM_VISITOR 81 | else { 82 | rlog("Resolving \"" << symbol << "\" to a global constant"); 83 | } 84 | #endif 85 | } 86 | #if DEBUG_LLVM_VISITOR 87 | else { 88 | if (GlobalValue::classof(target.value)) { 89 | rlog("Resolving \"" << symbol << "\" to a global & local constant"); 90 | } else { 91 | rlog("Resolving \"" << symbol << "\" to a local symbol"); 92 | } 93 | } 94 | #endif 95 | 96 | // Load an alloca or return a reference 97 | if (target.isAlloca()) { 98 | return builder_.CreateLoad(target.value, symbol->toString().c_str()); 99 | } else { 100 | return target.value; 101 | } 102 | } 103 | 104 | #include "_VisitorImplFooter.h" 105 | -------------------------------------------------------------------------------- /src/codegen/text_literal.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "_VisitorImplHeader.h" 4 | 5 | 6 | Value *Visitor::codegenTextLiteral(const ast::TextLiteral *textLit) { 7 | DEBUG_TRACE_LLVM_VISITOR; 8 | 9 | // Array type 10 | const Text& text = textLit->text(); 11 | ast::Type CoveCharType(ast::Type::Char); 12 | Type* elementT = IRTypeForASTType(&CoveCharType); 13 | ArrayType* arrayT = ArrayType::get(elementT, text.size()); 14 | 15 | // Make Constant values 16 | std::vector v; 17 | v.reserve(text.size()); 18 | Text::const_iterator it = text.begin(); 19 | size_t i = 0; 20 | for (; it != text.end(); ++it, ++i) { 21 | v.push_back( ConstantInt::get(getGlobalContext(), APInt(32, static_cast(*it), false)) ); 22 | } 23 | 24 | // Package as a constant array 25 | Constant* arrayV = ConstantArray::get(arrayT, makeArrayRef(v)); 26 | if (arrayV == 0) return error("Failed to create text constant array"); 27 | 28 | GlobalVariable* arrayGV = createArray(arrayV, "text"); 29 | 30 | Type* T = PointerType::get(getArrayStructType(elementT), 0); 31 | return builder_.CreatePointerCast(arrayGV, T); 32 | } 33 | 34 | #include "_VisitorImplFooter.h" 35 | -------------------------------------------------------------------------------- /src/codegen/type_conversion.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "_VisitorImplHeader.h" 4 | 5 | 6 | StructType* Visitor::getExplicitStructType(const ast::StructType* astST) { 7 | assert(module_ != 0); 8 | assert(astST != 0); 9 | std::string canonicalName = astST->canonicalName(); 10 | 11 | StructType *ST = module_->getTypeByName(canonicalName); 12 | if (ST) return ST; 13 | 14 | std::vector irTypes; 15 | irTypes.reserve(astST->size()); 16 | 17 | for (ast::TypeList::const_iterator I = astST->types().begin(), 18 | E = astST->types().end(); I != E; ++I) 19 | { 20 | llvm::Type *T = IRTypeForASTType(*I); 21 | if (T == 0) return 0; 22 | irTypes.push_back(T); 23 | } 24 | 25 | return StructType::create(llvm::getGlobalContext(), makeArrayRef(irTypes), 26 | canonicalName, astST->isPacked()); 27 | } 28 | 29 | 30 | llvm::FunctionType* Visitor::getLLVMFuncTypeForASTFuncType(const ast::FunctionType* astFT, 31 | llvm::Type* returnType) { 32 | // Build argument spec and create the function type: double(double,double) etc. 33 | if (returnType == 0) returnType = returnTypeForFunctionType(astFT); 34 | std::vector argSpec; 35 | if (!IRTypesForASTVariables(argSpec, astFT->args())) return 0; 36 | return FunctionType::get(returnType, argSpec, /*isVararg = */false); 37 | } 38 | 39 | 40 | StructType* Visitor::getArrayStructType(Type* elementType) { 41 | // { length i64, data elementType* } 42 | StructType *T = arrayStructTypes_[elementType]; 43 | if (T == 0) { 44 | Type *tv[2]; 45 | tv[0] = Type::getInt64Ty(getGlobalContext()); // i64 46 | //tv[1] = PointerType::get(Type::getInt8Ty(getGlobalContext()), 0); // i8* 47 | tv[1] = PointerType::get(elementType, 0); // i8* 48 | ArrayRef elementTypes = makeArrayRef(tv, 2); 49 | T = StructType::get(getGlobalContext(), elementTypes, /*isPacked = */true); 50 | arrayStructTypes_[elementType] = T; 51 | } 52 | return T; 53 | } 54 | 55 | 56 | llvm::Type *Visitor::IRTypeForASTType(const ast::Type* T) { 57 | if (T == 0) return builder_.getVoidTy(); 58 | switch (T->typeID()) { 59 | case ast::Type::Nil: return builder_.getInt1Ty(); 60 | case ast::Type::Float: return builder_.getDoubleTy(); 61 | case ast::Type::Int: return builder_.getInt64Ty(); 62 | case ast::Type::Char: return builder_.getInt32Ty(); 63 | case ast::Type::Byte: return builder_.getInt8Ty(); 64 | case ast::Type::Bool: return builder_.getInt1Ty(); 65 | 66 | case ast::Type::Array: { 67 | llvm::Type* elementType = 68 | IRTypeForASTType((reinterpret_cast(T))->type()); 69 | //return llvm::PointerType::get(elementType, 0); 70 | // Return a pointer to a struct of the array type: <{ i64, elementType* }>* 71 | return llvm::PointerType::get(getArrayStructType(elementType), 0); 72 | } 73 | 74 | case ast::Type::StructureT: { 75 | const ast::StructType* astST = static_cast(T); 76 | StructType *irST = getExplicitStructType(astST); 77 | return llvm::PointerType::get(irST, 0); 78 | } 79 | 80 | case ast::Type::FuncT: { 81 | const ast::FunctionType* astST = static_cast(T); 82 | llvm::FunctionType *FT = getLLVMFuncTypeForASTFuncType(astST); 83 | return llvm::PointerType::get(FT, 0); 84 | } 85 | 86 | //case ast::Type::Named: ... 87 | default: { 88 | error(std::string("No conversion from AST type ") + T->toString() + " to IR type"); 89 | return 0; 90 | } 91 | } 92 | } 93 | 94 | llvm::ArrayType* Visitor::getArrayTypeFromPointerType(llvm::Type* T) const { 95 | return ( T->isPointerTy() 96 | && T->getNumContainedTypes() == 1 97 | && llvm::ArrayType::classof(T = T->getContainedType(0)) 98 | ? static_cast(T) : 0 ); 99 | } 100 | 101 | ast::Type::TypeID Visitor::ASTTypeIDForIRType(const llvm::Type* T) { 102 | switch(T->getTypeID()) { 103 | case llvm::Type::VoidTyID: return ast::Type::Nil; 104 | case llvm::Type::DoubleTyID: return ast::Type::Float; 105 | case llvm::Type::IntegerTyID: { 106 | switch (T->getPrimitiveSizeInBits()) { 107 | case 1: return ast::Type::Bool; 108 | case 8: return ast::Type::Byte; 109 | case 32: return ast::Type::Char; 110 | case 64: return ast::Type::Int; 111 | default: return ast::Type::MaxTypeID; 112 | } 113 | } 114 | //case llvm::Type::FunctionTyID: 115 | // case StructTyID: return ///< 11: Structures 116 | // case ArrayTyID: return ///< 12: Arrays 117 | // case PointerTyID: return ///< 13: Pointers 118 | // case VectorTyID: return ///< 14: SIMD 'packed' format, or other vector type 119 | default: return ast::Type::MaxTypeID; 120 | } 121 | } 122 | 123 | ast::Type *Visitor::ASTTypeForIRType(const llvm::StructType* T) { 124 | return (ast::Type *)error("Not implemented: Visitor::ASTTypeForIRType(llvm::StructType)"); 125 | } 126 | 127 | ast::Type *Visitor::ASTTypeForIRType(const llvm::Type* T) { 128 | 129 | if (T->isPointerTy() && T->getContainedType(0)->isStructTy()) { 130 | llvm::StructType* ST = static_cast(T->getContainedType(0)); 131 | return ASTTypeForIRType(ST); 132 | } else { 133 | ast::Type::TypeID typeID = ASTTypeIDForIRType(T); 134 | return typeID == ast::Type::MaxTypeID ? 0 : new ast::Type(typeID); 135 | } 136 | } 137 | 138 | 139 | bool Visitor::IRTypesForASTVariables(std::vector& argSpec, ast::VariableList *argVars) { 140 | if (argVars != 0 && argVars->size() != 0) { 141 | argSpec.reserve(argVars->size()); 142 | ast::VariableList::const_iterator it = argVars->begin(); 143 | 144 | for (; it != argVars->end(); ++it) { 145 | ast::Variable* var = *it; 146 | 147 | // Type should be inferred? 148 | if (var->hasUnknownType()) { 149 | // TODO: runtime type inference support. 150 | return !!error("NOT IMPLEMENTED: runtime type inference of func arguments"); 151 | } 152 | 153 | // Lookup IR type for AST type 154 | Type* T = IRTypeForASTType(var->type()); 155 | if (T == 0) 156 | return !!error(R_FMT("No conversion for AST type " << var->toString() << " to IR type")); 157 | 158 | // Use T 159 | argSpec.push_back(T); 160 | } 161 | } 162 | 163 | return true; 164 | } 165 | 166 | 167 | #include "_VisitorImplFooter.h" 168 | -------------------------------------------------------------------------------- /src/fastcmp.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. 2 | // Use of this source code is governed by a MIT-style license that can be 3 | // found in the LICENSE file. 4 | // 5 | // Fast byte comparison. Inspired by Igor Sysoev's Nginx. 6 | // Works with LE systems that can handle 32-bit integers in one register. 7 | // 8 | #ifndef HUE__FASTCMP_H 9 | #define HUE__FASTCMP_H 10 | 11 | // bool hue_cmp(const T*, T1, ..) -- compare vector of T items of N length for equality 12 | 13 | #define hue_i8cmp2(m, c0, c1) ((m)[0] == c0 && (m)[1] == c1) 14 | 15 | #define hue_i8cmp3(m, c0, c1, c2) ((m)[0] == c0 && (m)[1] == c1 && (m)[2] == c2) 16 | 17 | #define hue_i8cmp4(m, c0, c1, c2, c3) \ 18 | (*(uint32_t *) (m) == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0)) 19 | 20 | #define hue_i8cmp5(m, c0, c1, c2, c3, c4) \ 21 | (*(uint32_t *) (m) == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) && (m)[4] == c4) 22 | 23 | #define hue_i8cmp6(m, c0, c1, c2, c3, c4, c5) \ 24 | (*(uint32_t *) (m) == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ 25 | && (((uint32_t *) (m))[1] & 0xffff) == ((c5 << 8) | c4)) 26 | 27 | #define hue_i8cmp7(m, c0, c1, c2, c3, c4, c5, c6) \ 28 | (*(uint32_t *) (m) == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ 29 | && (m)[4] == c4 && (m)[5] == c5 && (m)[6] == c6) 30 | 31 | #define hue_i8cmp8(m, c0, c1, c2, c3, c4, c5, c6, c7) \ 32 | (*(uint32_t *) (m) == ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0) \ 33 | && ((uint32_t *) (m))[1] == ((c7 << 24) | (c6 << 16) | (c5 << 8) | c4)) 34 | 35 | 36 | #define hue_i32cmp2(m, c0, c1) \ 37 | ( (m)[0] == ((uint32_t)(c0)) \ 38 | && (m)[1] == ((uint32_t)(c1)) ) 39 | 40 | #define hue_i32cmp3(m, c0, c1, c2) \ 41 | ( (m)[0] == ((uint32_t)(c0)) \ 42 | && (m)[1] == ((uint32_t)(c1)) \ 43 | && (m)[2] == ((uint32_t)(c2)) ) 44 | 45 | #define hue_i32cmp4(m, c0, c1, c2, c3) \ 46 | ( (m)[0] == ((uint32_t)(c0)) \ 47 | && (m)[1] == ((uint32_t)(c1)) \ 48 | && (m)[2] == ((uint32_t)(c2)) \ 49 | && (m)[3] == ((uint32_t)(c3)) ) 50 | 51 | #define hue_i32cmp5(m, c0, c1, c2, c3, c4) \ 52 | ( (m)[0] == ((uint32_t)(c0)) \ 53 | && (m)[1] == ((uint32_t)(c1)) \ 54 | && (m)[2] == ((uint32_t)(c2)) \ 55 | && (m)[3] == ((uint32_t)(c3)) \ 56 | && (m)[4] == ((uint32_t)(c4)) ) 57 | 58 | #define hue_i32cmp6(m, c0, c1, c2, c3, c4, c5) \ 59 | ( (m)[0] == ((uint32_t)(c0)) \ 60 | && (m)[1] == ((uint32_t)(c1)) \ 61 | && (m)[2] == ((uint32_t)(c2)) \ 62 | && (m)[3] == ((uint32_t)(c3)) \ 63 | && (m)[4] == ((uint32_t)(c4)) \ 64 | && (m)[5] == ((uint32_t)(c5)) ) 65 | 66 | #define hue_i32cmp7(m, c0, c1, c2, c3, c4, c5, c6) \ 67 | ( (m)[0] == ((uint32_t)(c0)) \ 68 | && (m)[1] == ((uint32_t)(c1)) \ 69 | && (m)[2] == ((uint32_t)(c2)) \ 70 | && (m)[3] == ((uint32_t)(c3)) \ 71 | && (m)[4] == ((uint32_t)(c4)) \ 72 | && (m)[5] == ((uint32_t)(c5)) \ 73 | && (m)[6] == ((uint32_t)(c6)) ) 74 | 75 | #define hue_i32cmp8(m, c0, c1, c2, c3, c4, c5, c6, c7) \ 76 | ( (m)[0] == ((uint32_t)(c0)) \ 77 | && (m)[1] == ((uint32_t)(c1)) \ 78 | && (m)[2] == ((uint32_t)(c2)) \ 79 | && (m)[3] == ((uint32_t)(c3)) \ 80 | && (m)[4] == ((uint32_t)(c4)) \ 81 | && (m)[5] == ((uint32_t)(c5)) \ 82 | && (m)[6] == ((uint32_t)(c6)) \ 83 | && (m)[7] == ((uint32_t)(c7)) ) 84 | 85 | #endif // HUE__FASTCMP_H 86 | 87 | // uint8_t *m = new uint8_t[sizeof("abcdefghijklmnopqrstuvwxyz")]; 88 | // memcpy(m, "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")); 89 | // cout << "hue_i8cmp2: " << hue_i8cmp2(m, 'a','b') << " " << hue_i8cmp2(m, 'z','y') << endl; 90 | // cout << "hue_i8cmp3: " << hue_i8cmp3(m, 'a','b','c') << " " << hue_i8cmp3(m, 'z','y','x') << endl; 91 | // cout << "hue_i8cmp4: " << hue_i8cmp4(m, 'a','b','c','d') << " " << hue_i8cmp4(m, 'z','y','y','y') << endl; 92 | // cout << "hue_i8cmp5: " << hue_i8cmp5(m, 'a','b','c','d','e') << " " << hue_i8cmp5(m, 'z','y','y','y','y') << endl; 93 | // cout << "hue_i8cmp6: " << hue_i8cmp6(m, 'a','b','c','d','e','f') << " " << hue_i8cmp6(m, 'z','y','c','d','e','x') << endl; 94 | // cout << "hue_i8cmp7: " << hue_i8cmp7(m, 'a','b','c','d','e','f','g') << " " << hue_i8cmp7(m, 'z','y','c','d','e','f','g') << endl; 95 | // cout << "hue_i8cmp8: " << hue_i8cmp8(m, 'a','b','c','d','e','f','g','h') << " " << hue_i8cmp8(m, 'z','y','c','d','e','f','g','h') << endl; 96 | // cout << "hue_i8cmp9: " << hue_i8cmp9(m, 'a','b','c','d','e','f','g','h','i') << " " << hue_i8cmp9(m, 'z','y','c','d','e','f','g','h','i') << endl; 97 | -------------------------------------------------------------------------------- /src/linenoise/.gitignore: -------------------------------------------------------------------------------- 1 | linenoise_example 2 | -------------------------------------------------------------------------------- /src/linenoise/Makefile: -------------------------------------------------------------------------------- 1 | linenoise_example: linenoise.h linenoise.c 2 | 3 | linenoise_example: linenoise.c example.c 4 | $(CC) -Wall -W -Os -g -o linenoise_example linenoise.c example.c 5 | 6 | clean: 7 | rm -f linenoise_example 8 | -------------------------------------------------------------------------------- /src/linenoise/README.markdown: -------------------------------------------------------------------------------- 1 | # Linenoise 2 | 3 | A minimal, zero-config, BSD licensed, readline replacement. 4 | 5 | News: linenoise now includes minimal completion support, thanks to Pieter Noordhuis (@pnoordhuis). 6 | 7 | News: linenoise is now part of [Android](http://android.git.kernel.org/?p=platform/system/core.git;a=tree;f=liblinenoise;h=56450eaed7f783760e5e6a5993ef75cde2e29dea;hb=HEAD Android)! 8 | 9 | ## Can a line editing library be 20k lines of code? 10 | 11 | Line editing with some support for history is a really important feature for command line utilities. Instead of retyping almost the same stuff again and again it's just much better to hit the up arrow and edit on syntax errors, or in order to try a slightly different command. But apparently code dealing with terminals is some sort of Black Magic: readline is 30k lines of code, libedit 20k. Is it reasonable to link small utilities to huge libraries just to get a minimal support for line editing? 12 | 13 | So what usually happens is either: 14 | 15 | * Large programs with configure scripts disabling line editing if readline is not present in the system, or not supporting it at all since readline is GPL licensed and libedit (the BSD clone) is not as known and available as readline is (Readl world example of this problem: Tclsh). 16 | * Smaller programs not using a configure script not supporting line editing at all (A problem we had with Redis-cli for instance). 17 | 18 | The result is a pollution of binaries without line editing support. 19 | 20 | So I spent more or less two hours doing a reality check resulting in this little library: is it *really* needed for a line editing library to be 20k lines of code? Apparently not, it is possibe to get a very small, zero configuration, trivial to embed library, that solves the problem. Smaller programs will just include this, supporing line editing out of the box. Larger programs may use this little library or just checking with configure if readline/libedit is available and resorting to linenoise if not. 21 | 22 | ## Terminals, in 2010. 23 | 24 | Apparently almost every terminal you can happen to use today has some kind of support for VT100 alike escape sequences. So I tried to write a lib using just very basic VT100 features. The resulting library appears to work everywhere I tried to use it. 25 | 26 | Since it's so young I guess there are a few bugs, or the lib may not compile or work with some operating system, but it's a matter of a few weeks and eventually we'll get it right, and there will be no excuses for not shipping command line tools without built-in line editing support. 27 | 28 | The library is currently less than 400 lines of code. In order to use it in your project just look at the *example.c* file in the source distribution, it is trivial. Linenoise is BSD code, so you can use both in free software and commercial software. 29 | 30 | ## Tested with... 31 | 32 | * Linux text only console ($TERM = linux) 33 | * Linux KDE terminal application ($TERM = xterm) 34 | * Linux xterm ($TERM = xterm) 35 | * Mac OS X iTerm ($TERM = xterm) 36 | * Mac OS X default Terminal.app ($TERM = xterm) 37 | * OpenBSD 4.5 through an OSX Terminal.app ($TERM = screen) 38 | * IBM AIX 6.1 39 | * FreeBSD xterm ($TERM = xterm) 40 | 41 | Please test it everywhere you can and report back! 42 | 43 | ## Let's push this forward! 44 | 45 | Please fork it and add something interesting and send me a pull request. What's especially interesting are fixes, new key bindings, completion. 46 | 47 | Send feedbacks to antirez at gmail 48 | -------------------------------------------------------------------------------- /src/linenoise/example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "linenoise.h" 4 | 5 | 6 | void completion(const char *buf, linenoiseCompletions *lc) { 7 | if (buf[0] == 'h') { 8 | linenoiseAddCompletion(lc,"hello"); 9 | linenoiseAddCompletion(lc,"hello there"); 10 | } 11 | } 12 | 13 | int main(void) { 14 | char *line; 15 | 16 | linenoiseSetCompletionCallback(completion); 17 | linenoiseHistoryLoad("history.txt"); /* Load the history at startup */ 18 | while((line = linenoise("hello> ")) != NULL) { 19 | if (line[0] != '\0') { 20 | printf("echo: '%s'\n", line); 21 | linenoiseHistoryAdd(line); 22 | linenoiseHistorySave("history.txt"); /* Save every new entry */ 23 | } 24 | free(line); 25 | } 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /src/linenoise/linenoise.h: -------------------------------------------------------------------------------- 1 | /* linenoise.h -- guerrilla line editing library against the idea that a 2 | * line editing lib needs to be 20,000 lines of C code. 3 | * 4 | * See linenoise.c for more information. 5 | * 6 | * ------------------------------------------------------------------------ 7 | * 8 | * Copyright (c) 2010, Salvatore Sanfilippo 9 | * Copyright (c) 2010, Pieter Noordhuis 10 | * 11 | * All rights reserved. 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions are 15 | * met: 16 | * 17 | * * Redistributions of source code must retain the above copyright 18 | * notice, this list of conditions and the following disclaimer. 19 | * 20 | * * Redistributions in binary form must reproduce the above copyright 21 | * notice, this list of conditions and the following disclaimer in the 22 | * documentation and/or other materials provided with the distribution. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 30 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #ifndef __LINENOISE_H 38 | #define __LINENOISE_H 39 | 40 | typedef struct linenoiseCompletions { 41 | size_t len; 42 | char **cvec; 43 | } linenoiseCompletions; 44 | 45 | typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); 46 | void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); 47 | void linenoiseAddCompletion(linenoiseCompletions *, const char *); 48 | 49 | char *linenoise(const char *prompt); 50 | int linenoiseHistoryAdd(const char *line, int allowDuplicates); 51 | int linenoiseHistorySetMaxLen(int len); 52 | int linenoiseHistorySave(const char *filename); 53 | int linenoiseHistoryLoad(const char *filename); 54 | void linenoiseClearScreen(void); 55 | 56 | #endif /* __LINENOISE_H */ 57 | -------------------------------------------------------------------------------- /src/parse/ByteInput.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | // Baseclass for byte inputs, providing limited random access to a sequence of bytes 5 | #ifndef HUE__BYTE_INPUT_H 6 | #define HUE__BYTE_INPUT_H 7 | 8 | #include 9 | #include 10 | 11 | namespace hue { 12 | 13 | class ByteInput { 14 | public: 15 | virtual bool started() const = 0; 16 | virtual bool ended() const = 0; 17 | virtual bool failed() const = 0; 18 | virtual const uint8_t& next(const size_t stride = 1) = 0; 19 | virtual const uint8_t& past(size_t offset) const = 0; 20 | virtual const uint8_t& current() const = 0; 21 | virtual const uint8_t& future(size_t offset) const = 0; 22 | virtual size_t pastCount() const = 0; 23 | virtual size_t futureCount() const = 0; 24 | virtual const uint8_t *data(size_t &size) const = 0; 25 | }; 26 | 27 | static const uint8_t InputEnd = 0; 28 | 29 | } // namespace hue 30 | 31 | #endif // HUE__BYTE_INPUT_H 32 | -------------------------------------------------------------------------------- /src/parse/FileInput.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | // A StreamInput (: ByteInput) that reads from a file 5 | #ifndef HUE__FILE_INPUT_H 6 | #define HUE__FILE_INPUT_H 7 | 8 | #include "StreamInput.h" 9 | #include 10 | 11 | namespace hue { 12 | 13 | template 14 | class FileInput : public StreamInput { 15 | public: 16 | explicit FileInput(const char* filename) : StreamInput() { 17 | StreamInput::setInputStream( 18 | new std::ifstream(filename, std::ifstream::in | std::ifstream::binary), true); 19 | } 20 | 21 | virtual ~FileInput() { 22 | if (((std::ifstream*)this->inputStream())->is_open()) { 23 | ((std::ifstream*)this->inputStream())->close(); 24 | } 25 | } 26 | }; 27 | 28 | } // namespace hue 29 | 30 | #endif // HUE__FILE_INPUT_H 31 | -------------------------------------------------------------------------------- /src/parse/StreamInput.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | // A ByteInput implementation that reads from a standard input stream 5 | #ifndef HUE__STREAM_INPUT_H 6 | #define HUE__STREAM_INPUT_H 7 | 8 | #include "ByteInput.h" 9 | #include 10 | 11 | namespace hue { 12 | 13 | template 14 | class StreamInput : public ByteInput { 15 | std::istream *istream_; 16 | bool owns_istream_; 17 | size_t start_; // index of oldest element 18 | size_t count_; // number of used elements 19 | size_t next_; // current element index (offset from start_) 20 | size_t current_; 21 | uint8_t elems_[BufferSize]; // vector of elements 22 | public: 23 | explicit StreamInput(std::istream *ins = NULL, bool takeOwnership = false) 24 | : istream_(ins), owns_istream_(takeOwnership), start_(0), count_(0), next_(0), current_(0) {} 25 | 26 | virtual ~StreamInput() { 27 | if (owns_istream_ && istream_) delete istream_; 28 | } 29 | 30 | const std::istream* inputStream() const { return istream_; } 31 | void setInputStream(std::istream *ins, bool takeOwnership = false) { 32 | std::istream *istream1 = owns_istream_ ? istream_ : NULL; 33 | istream_ = ins; 34 | owns_istream_ = takeOwnership; 35 | if (istream1) delete istream1; 36 | } 37 | 38 | const size_t size() const { return BufferSize; } 39 | const size_t &count() const { return count_; } 40 | 41 | bool failed() const { return istream_->fail(); } 42 | bool started() const { return count_ != 0; } 43 | bool isFull() const { return count_ == BufferSize; } 44 | int isEmpty() const { return count_ == 0; } 45 | 46 | void push(const uint8_t &elem) { 47 | size_t end = (start_ + count_) % BufferSize; 48 | elems_[end] = elem; 49 | if (count_ == BufferSize) { 50 | start_ = (start_ + 1) % BufferSize; // full, overwrite 51 | -- next_; 52 | } else { 53 | ++ count_; 54 | } 55 | } 56 | 57 | void pop(uint8_t &elem) { 58 | elem = elems_[start_]; 59 | start_ = (start_ + 1) % BufferSize; 60 | -- next_; 61 | -- count_; 62 | } 63 | 64 | void pushFromStream(size_t limit) { 65 | if (limit > BufferSize) { 66 | limit = BufferSize; 67 | } 68 | 69 | //std::cout << "read " << limit << " \""; 70 | while (istream_->good() && limit--) { 71 | char byte; 72 | istream_->get(byte); 73 | if (istream_->eof()) { 74 | //std::cout << ""; 75 | break; 76 | } 77 | //std::cout << byte; 78 | push((const uint8_t &)byte); 79 | } 80 | //std::cout << "\"" << std::endl; 81 | } 82 | 83 | bool ended() const { 84 | return current_ == count_; 85 | } 86 | 87 | const uint8_t& next(const size_t stride = 1) { 88 | size_t lowWatermark = BufferSize / 3; 89 | size_t futurec = futureCount(); 90 | 91 | if (futurec < lowWatermark && !istream_->eof()) { 92 | //std::cout << "Filling from stream... " << std::endl; 93 | size_t readLimit; 94 | if (!isFull() && futurec == 0) { 95 | readLimit = BufferSize; // first read 96 | } else { 97 | readLimit = BufferSize / 2; 98 | } 99 | pushFromStream(readLimit); 100 | //cout << "count_: " << count_ << endl; 101 | } else if (futurec == 0 && istream_->eof()) { 102 | current_ = count_; 103 | return InputEnd; 104 | } 105 | 106 | current_ = (start_ + next_ + (stride - 1)) % BufferSize; 107 | next_ += stride; 108 | return elems_[current_]; 109 | } 110 | 111 | const uint8_t& past(size_t offset) const { 112 | size_t cur = (start_ + next_ - offset - 2) % BufferSize; 113 | return elems_[cur]; 114 | } 115 | 116 | const uint8_t& current() const { 117 | if (current_ == count_) { 118 | return InputEnd; 119 | } else { 120 | return elems_[current_]; 121 | } 122 | } 123 | 124 | const uint8_t& future(size_t offset) const { 125 | size_t cur = (start_ + next_ + offset) % BufferSize; 126 | return elems_[cur]; 127 | } 128 | 129 | size_t pastCount() const { 130 | return count_ - (count_ - next_ + 1); 131 | } 132 | 133 | size_t futureCount() const { 134 | return count_ - next_; 135 | } 136 | 137 | const uint8_t *data(size_t &size) const { 138 | size = count_ - current_; 139 | return elems_ + current_; 140 | } 141 | }; 142 | 143 | } // namespace hue 144 | 145 | #endif // HUE__STREAM_INPUT_H 146 | -------------------------------------------------------------------------------- /src/parse/Token.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | // Represents the simplest parts of the language: lexical tokens 5 | #ifndef HUE__TOKEN_H 6 | #define HUE__TOKEN_H 7 | 8 | #include "../Text.h" 9 | #include 10 | 11 | namespace hue { 12 | 13 | typedef struct { 14 | const char *name; 15 | const bool hasTextValue; 16 | const bool hasDoubleValue; 17 | const bool hasIntValue; 18 | } TokenTypeInfo; 19 | 20 | class Token { 21 | public: 22 | enum Type { 23 | Unexpected = 0, 24 | Comment, // #.+ 25 | Func, // 'func' ... 26 | External, // "extern" 27 | Mutable, // "MUTABLE" 28 | Identifier, 29 | BinaryOperator, // '+', '*', '>', etc. 30 | BinaryComparisonOperator, // '!=' '<=' '>=' '=='. First byte is key. 31 | MapLiteral, 32 | RightArrow, // '->' 33 | LeftArrow, // '<-' 34 | LeftParen, // '(' 35 | RightParen, // ')' 36 | LeftSqBracket, // '[' 37 | RightSqBracket, // ']' 38 | Comma, // ',' 39 | Stop, // '.' 40 | Assignment, // '=' 41 | Backslash, // '\' 42 | Question, // '?' 43 | Colon, // ':' 44 | Semicolon, // ';' 45 | NewLine, 46 | 47 | // Literals 48 | IntLiteral, 49 | FloatLiteral, 50 | BoolLiteral, // intValue denotes value: 0 = false, !0 = true 51 | TextLiteral, // textValue is the data 52 | DataLiteral, // textValue is the data 53 | // TODO: BinaryLiteral 54 | 55 | // Symbols 56 | IntSymbol, // 'Int' 57 | FloatSymbol, // 'Float' 58 | Bool, // 'Bool' 59 | Byte, // 'Byte' 60 | Char, // 'Char' 61 | 62 | If, // 'if' 63 | Else, // 'else' 64 | Nil, // 'nil' 65 | 66 | Structure, // 'struct' 67 | 68 | // Special meaning 69 | Error, // textValue = message, intValue = code 70 | End, 71 | 72 | _TypeCount, 73 | } type; 74 | // The above enum MUST be aligned with the following array: 75 | static const TokenTypeInfo TypeInfo[_TypeCount]; 76 | 77 | // For tokens that encode flags into intValue 78 | enum IntFlags { 79 | Flag_Namespaced = 1, 80 | Flag_Path = 2, 81 | }; 82 | 83 | Text textValue; 84 | union { 85 | double doubleValue; 86 | uint8_t intValue; 87 | }; 88 | 89 | uint32_t line; 90 | uint32_t column; 91 | uint32_t length; 92 | 93 | Token(Type type = _TypeCount) : type(type), line(0), column(0), length(0) {} 94 | Token(const Token &other) { assign(other); } 95 | 96 | void assign(const Token &other) { 97 | type = other.type; 98 | line = other.line; 99 | column = other.column; 100 | length = other.length; 101 | 102 | // Value 103 | if (type >= 0 && type < _TypeCount) { 104 | const TokenTypeInfo& info = TypeInfo[type]; 105 | 106 | if (info.hasTextValue) 107 | textValue = other.textValue; 108 | 109 | if (info.hasDoubleValue) { 110 | doubleValue = other.doubleValue; 111 | } else if (info.hasIntValue) { 112 | intValue = other.intValue; 113 | } 114 | } 115 | } 116 | 117 | bool isNull() const { return type == _TypeCount; } 118 | 119 | inline bool isIdentifier() const { return type == Identifier; } 120 | inline bool isNamespacedIdentifier() const { 121 | return isIdentifier() && (intValue & Flag_Namespaced); 122 | } 123 | inline bool isIdentifierWithPath() const { 124 | return isIdentifier() && (intValue & Flag_Path); 125 | } 126 | 127 | const char *typeName() const { 128 | if (type >= 0 && type < _TypeCount) { 129 | return TypeInfo[type].name; 130 | } else { 131 | return "?"; 132 | } 133 | } 134 | 135 | std::string toString() const { 136 | #define return_fstr(fmt, ...) do { \ 137 | const size_t bufsize = 512; \ 138 | char buf[bufsize+1]; \ 139 | snprintf(buf, bufsize, fmt, __VA_ARGS__); \ 140 | return std::string(buf); \ 141 | } while (0) 142 | 143 | if (type >= 0 && type < _TypeCount) { 144 | const TokenTypeInfo& info = TypeInfo[type]; 145 | if (info.hasTextValue) { 146 | return_fstr("%s@%u:%u,%u = %s", info.name, line, column, length, textValue.UTF8String().c_str()); 147 | } else if (info.hasDoubleValue) { 148 | return_fstr("%s@%u:%u,%u = %f", info.name, line, column, length, doubleValue); 149 | } else if (info.hasIntValue) { 150 | return_fstr("%s@%u:%u,%u = %d", info.name, line, column, length, intValue); 151 | } else { 152 | return_fstr("%s@%u:%u,%u", info.name, line, column, length); 153 | } 154 | } else { 155 | return "?"; 156 | } 157 | } 158 | 159 | inline Token& operator= (const Token& rhs) { 160 | assign(rhs); return *this; 161 | } 162 | }; 163 | 164 | static const Token NullToken; 165 | 166 | const TokenTypeInfo Token::TypeInfo[] = { 167 | // name // hasTextValue hasDoubleValue hasIntValue 168 | {"Unexpected", .hasTextValue = 1, 0,0}, 169 | {"Comment", .hasTextValue = 1, 0,0}, 170 | {"Func", 0,0,0}, 171 | {"External", 0,0,0}, 172 | {"Mutable", 0,0,0}, 173 | {"Identifier", .hasTextValue = 1, 0, .hasIntValue = 1}, // intValue = flags (enum IntFlags) 174 | {"BinaryOperator", .hasTextValue = 1, 0,0}, 175 | {"BinaryComparisonOperator", .hasTextValue = 1, 0,0}, 176 | {"MapLiteral", 0,0,0}, 177 | {"RightArrow", 0,0,0}, 178 | {"LeftArrow", 0,0,0}, 179 | {"LeftParen", 0,0,0}, 180 | {"RightParen", 0,0,0}, 181 | {"LeftSqBracket", 0,0,0}, 182 | {"RightSqBracket", 0,0,0}, 183 | {"Comma", 0,0,0}, 184 | {"Stop", 0,0,0}, 185 | {"Assignment", 0,0,0}, 186 | {"Backslash", 0,0,0}, 187 | {"Question", 0,0,0}, 188 | {"Colon", 0,0,0}, 189 | {"Semicolon", 0,0,0}, 190 | {"NewLine", 0,0,0}, 191 | 192 | {"IntLiteral", .hasTextValue = 1,0, .hasIntValue = 1}, // intValue = radix 193 | {"FloatLiteral", .hasTextValue = 1,0,0}, 194 | {"BoolLiteral", 0,0, .hasIntValue = 1}, // intValue = !0 195 | {"TextLiteral", .hasTextValue = 1,0,0}, 196 | {"DataLiteral", .hasTextValue = 1,0,0}, 197 | 198 | {"IntSymbol", 0,0,0}, // i64 199 | {"FloatSymbol", 0,0,0}, // double 200 | {"Bool", 0,0,0}, // i1 201 | {"Byte", 0,0,0}, // i8 202 | {"Char", 0,0,0}, // i32 203 | 204 | {"If", 0,0,0}, 205 | {"Else", 0,0,0}, 206 | {"Nil", 0,0,0}, 207 | 208 | {"Structure", 0,0,0}, 209 | 210 | {"Error", .hasTextValue = 1,0, .hasIntValue = 1}, 211 | {"End", 0,0,0}, 212 | }; 213 | 214 | } // namespace hue 215 | 216 | #endif // HUE__TOKEN_H 217 | -------------------------------------------------------------------------------- /src/parse/TokenBuffer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | // A buffer that reads tokens from a Tokenizer and keeps N historical 5 | // tokens around. 6 | #ifndef HUE__TOKEN_BUFFER_H 7 | #define HUE__TOKEN_BUFFER_H 8 | 9 | #include "Token.h" 10 | #include "Tokenizer.h" 11 | 12 | namespace hue { 13 | 14 | #define TokenBufferSize 16 15 | 16 | class TokenBuffer { 17 | Tokenizer &tokenizer_; 18 | size_t start_; // index of oldest element 19 | size_t count_; // number of used elements 20 | size_t next_; // index of oldest element 21 | Token tokens_[TokenBufferSize]; // vector of elements 22 | 23 | public: 24 | explicit TokenBuffer(Tokenizer &tokenizer) : tokenizer_(tokenizer), start_(0), count_(0), next_(0) {} 25 | 26 | const size_t size() const { return TokenBufferSize; } 27 | const size_t& count() const { return count_; } 28 | 29 | void push(const Token& token) { 30 | size_t end = (start_ + count_) % TokenBufferSize; 31 | tokens_[end] = token; 32 | if (count_ == TokenBufferSize) { 33 | start_ = (start_ + 1) % TokenBufferSize; // full, overwrite 34 | } else { 35 | ++count_; 36 | } 37 | } 38 | 39 | // const Token& pop() { 40 | // size_t start = start_; 41 | // start_ = (start_ + 1) % TokenBufferSize; 42 | // --count_; 43 | // return tokens_[start]; 44 | // } 45 | 46 | const Token& next() { 47 | const Token& token = tokenizer_.next(); 48 | push(token); 49 | ++next_; 50 | return token; 51 | } 52 | 53 | // History access. 0=last token returned by next(), N=N tokens back in time 54 | const Token& operator[](size_t index) const { 55 | size_t i; 56 | if (count_ == TokenBufferSize) { 57 | i = (start_ + (count_ - (index + 1))) % TokenBufferSize; 58 | } else { 59 | i = count_ - (index + 1); 60 | } 61 | return tokens_[i]; 62 | } 63 | }; 64 | 65 | 66 | } // namespace hue 67 | 68 | #endif // HUE__TOKEN_BUFFER_H 69 | -------------------------------------------------------------------------------- /src/runtime/Vector.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "Vector.h" 4 | 5 | namespace hue { 6 | 7 | const Vector Vector::_Empty; 8 | Vector* Vector::Empty = (Vector*)&Vector::_Empty; 9 | 10 | const Vector::Node Vector::Node::_Empty; 11 | Vector::Node* Vector::Node::Empty = (Vector::Node*)&Vector::Node::_Empty; 12 | 13 | 14 | // ------------------------------------------------------ 15 | // Vector::Node 16 | 17 | std::string Vector::Node::repr() const { 18 | std::ostringstream ss; 19 | ss << "repr(); 23 | } else { 24 | ss << ((size_t*)&data)[i]; 25 | } 26 | if (i < length-1) ss << ", "; 27 | } 28 | ss << "]>"; 29 | return ss.str(); 30 | } 31 | 32 | } // namespace hue 33 | -------------------------------------------------------------------------------- /src/runtime/object.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | #ifndef _HUE_OBJECT_INCLUDED 5 | #define _HUE_OBJECT_INCLUDED 6 | 7 | #include 8 | #include 9 | 10 | // Memory 11 | #define hue_alloc malloc 12 | #define hue_realloc realloc 13 | #define hue_dealloc free 14 | 15 | namespace hue { 16 | 17 | // Reference counter 18 | typedef uint64_t Ref; 19 | 20 | // Reference counter value that denotes the owner is not retainable. 21 | // Calling retain or release on such an object has no effect. 22 | // This is useful for globals that might be mixed with reference counted 23 | // objects of the same kind. 24 | static const Ref Unretainable = UINT64_MAX; 25 | 26 | // Reference ownership rules 27 | typedef enum { 28 | RetainReference = 0, // ownership is retained (reference count is increased by the receiver) 29 | TransferReference, // ownership is transfered ("steals" a reference) 30 | } RefRule; 31 | 32 | // Implements the functions and data needed for a class to become reference counted. 33 | // Messy, but it works... 34 | #define HUE_OBJECT(T) \ 35 | public: \ 36 | Ref refcount_; \ 37 | private: \ 38 | static T* __alloc(size_t size = sizeof(T)) { \ 39 | T* obj = (T*)hue_alloc(size); \ 40 | obj->refcount_ = 1; \ 41 | return obj; \ 42 | } \ 43 | public: \ 44 | inline T* retain() { \ 45 | if (refcount_ != hue::Unretainable) __sync_add_and_fetch(&refcount_, 1); \ 46 | return this; \ 47 | } \ 48 | inline void release() { \ 49 | if (refcount_ != hue::Unretainable && __sync_sub_and_fetch(&refcount_, 1) == 0) { \ 50 | dealloc(); \ 51 | hue_dealloc(this); \ 52 | } \ 53 | } \ 54 | protected: 55 | 56 | 57 | //class Object { HUE_OBJECT(Object) void dealloc() {} }; 58 | 59 | // ------------------------- 60 | // Debugging 61 | 62 | // Increment or decrement a counter (*counter* must be a non-bit-field 32- or 64-bit integer) 63 | #define HUE_DEBUG_COUNT_INC(counter) __sync_add_and_fetch(&(counter), 1) 64 | #define HUE_DEBUG_COUNT_DEC(counter) __sync_sub_and_fetch(&(counter), 1) 65 | 66 | } // namespace hue 67 | #endif // _HUE_OBJECT_INCLUDED 68 | -------------------------------------------------------------------------------- /src/runtime/runtime.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | 4 | //#define RT_TRACE printf("RT_TRACE: %s (%s:%d)\n", __PRETTY_FUNCTION__, __FILE__, __LINE__); 5 | #define RT_TRACE 6 | 7 | #include "../utf8/unchecked.h" 8 | #include "runtime.h" 9 | 10 | #include 11 | #include 12 | 13 | #define _writef(z, fmt, ...) do { \ 14 | char buf[z+1]; \ 15 | int len = snprintf(buf, z+1, fmt, __VA_ARGS__); \ 16 | write(STDOUT_FILENO, buf, len); \ 17 | } while(0) 18 | 19 | namespace hue { 20 | 21 | void stdout_write(const Bool v) { 22 | if (v) write(STDOUT_FILENO, "true", 4); 23 | else write(STDOUT_FILENO, "false", 5); 24 | } 25 | 26 | void stdout_write(const Float v) { _writef(32, "%f", v); } 27 | void stdout_write(const Int v) { _writef(32, "%lld", v); } 28 | void stdout_write(const Byte v) { _writef(32, "%x", v); } 29 | 30 | void stdout_write(const UChar v) { 31 | std::string utf8string = Text::UCharToUTF8String(v); 32 | write(STDOUT_FILENO, utf8string.data(), utf8string.size()); 33 | } 34 | 35 | void stdout_write(const DataS data) { 36 | RT_TRACE 37 | write(STDOUT_FILENO, data->data, data->length); 38 | } 39 | 40 | void stdout_write(const TextS text) { 41 | RT_TRACE 42 | std::string utf8string; 43 | std::back_insert_iterator it = std::back_inserter(utf8string); 44 | Int i = 0; 45 | for (; i != text->length; ++i) { 46 | utf8::unchecked::append(text->data[i], it); 47 | } 48 | write(STDOUT_FILENO, utf8string.data(), utf8string.size()); 49 | } 50 | 51 | } // namespace hue 52 | -------------------------------------------------------------------------------- /src/runtime/runtime.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #ifndef _HUE_RUNTIME_INCLUDED 4 | #define _HUE_RUNTIME_INCLUDED 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace hue { 13 | 14 | // Types 15 | typedef double Float; 16 | typedef int64_t Int; 17 | // UChar is defined by Text.h 18 | typedef uint8_t Byte; 19 | typedef bool Bool; 20 | typedef struct DataS_ { Int length; Byte data[0]; }* DataS; 21 | typedef struct TextS_ { Int length; UChar data[0]; }* TextS; 22 | 23 | // Write a value to stdout. Mostly for testing and debugging. 24 | void stdout_write(const Bool v); // _ZN3hue12stdout_writeEb 25 | void stdout_write(const Float v); // _ZN3hue12stdout_writeEd 26 | void stdout_write(const Int v); // _ZN3hue12stdout_writeEx 27 | void stdout_write(const UChar v); // _ZN3hue12stdout_writeEj 28 | void stdout_write(const Byte v); // _ZN3hue12stdout_writeEh 29 | void stdout_write(const DataS data); // _ZN3hue12stdout_writeEPNS_6DataS_E 30 | void stdout_write(const TextS data); // _ZN3hue12stdout_writeEPNS_6TextS_E 31 | 32 | } // namespace hue 33 | #endif // _HUE_RUNTIME_INCLUDED 34 | -------------------------------------------------------------------------------- /src/termstyle.h: -------------------------------------------------------------------------------- 1 | #ifndef HUE_TERMINAL_STYLE_INCLUDED 2 | #define HUE_TERMINAL_STYLE_INCLUDED 3 | 4 | // Terminal styles 5 | #define TS_None "\e[0m" 6 | 7 | #define TS_Black "\e[0;30m" 8 | #define TS_Blue "\e[0;34m" 9 | #define TS_Green "\e[0;32m" 10 | #define TS_Cyan "\e[0;36m" 11 | #define TS_Red "\e[0;31m" 12 | #define TS_Purple "\e[0;35m" 13 | #define TS_Brown "\e[0;33m" 14 | #define TS_Light_Gray "\e[0;37m" 15 | #define TS_Dark_Gray "\e[1;30m" 16 | #define TS_Light_Blue "\e[1;34m" 17 | #define TS_Light_Green "\e[1;32m" 18 | #define TS_Light_Cyan "\e[1;36m" 19 | #define TS_Light_Red "\e[1;31m" 20 | #define TS_Light_Purple "\e[1;35m" 21 | #define TS_Yellow "\e[1;33m" 22 | #define TS_White "\e[1;37m" 23 | 24 | #define TS_Black_BG "\e[40m" 25 | #define TS_Red_BG "\e[41m" 26 | #define TS_Green_BG "\e[42m" 27 | #define TS_Brown_BG "\e[43m" 28 | #define TS_Blue_BG "\e[44m" 29 | #define TS_Purple_BG "\e[45m" 30 | #define TS_Cyan_BG "\e[46m" 31 | #define TS_Light_Gray_BG "\e[47m" 32 | 33 | #endif // HUE_TERMINAL_STYLE_INCLUDED 34 | -------------------------------------------------------------------------------- /src/transform/LazyFuncResultTransformer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #ifndef _HUE_TRANSFORM_LFR_TRANSFORMER_INCLUDED 4 | #define _HUE_TRANSFORM_LFR_TRANSFORMER_INCLUDED 5 | 6 | #define DEBUG_TRANSFORM_LFR_VISITOR 1 7 | #if DEBUG_LLVM_VISITOR 8 | #include "../DebugTrace.h" 9 | #define DEBUG_TRACE_LFR_VISITOR DEBUG_TRACE 10 | #else 11 | #define DEBUG_TRACE_LFR_VISITOR do{}while(0) 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "Scope.h" 22 | 23 | namespace hue { namespace transform { 24 | 25 | class LazyFuncResultTransformer : public Scoped { 26 | 27 | class Scope : public transform::Scope { 28 | public: 29 | Scope(Scoped* parent) : transform::Scope(parent), termType(0) {} 30 | ast::Type* termType; 31 | }; 32 | 33 | 34 | public: 35 | LazyFuncResultTransformer(ast::Block* block) : block_(block) {} 36 | 37 | Scope* currentScope() const { return (Scope*)Scoped::currentScope(); } 38 | 39 | bool run(std::string& errmsg) { 40 | assert(block_ != 0); 41 | bool ok = visitBlock(block_); 42 | if (!ok) 43 | errmsg.assign(errs_.str()); 44 | errs_.str(""); 45 | errs_.clear(); 46 | return ok; 47 | } 48 | 49 | bool error(std::ostream& ss) { 50 | ss << std::endl; 51 | return false; 52 | } 53 | 54 | // --------------------------------------------------------------- 55 | 56 | bool visit(ast::Node* node) { 57 | DEBUG_TRACE_LFR_VISITOR; 58 | switch (node->nodeTypeID()) { 59 | #define VISIT(Name) \ 60 | case ast::Node::T##Name: return visit##Name(static_cast(node)); 61 | 62 | // Node types 63 | // VISIT(FunctionType); 64 | // VISIT(Variable); 65 | 66 | // Expression types 67 | VISIT(Function); 68 | //VISIT(ExternalFunction); 69 | VISIT(Block); // currently never hit 70 | VISIT(Symbol); 71 | VISIT(Assignment); 72 | VISIT(BinaryOp); 73 | VISIT(Call); 74 | VISIT(Conditional); 75 | //VISIT(IntLiteral); 76 | //VISIT(FloatLiteral); 77 | //VISIT(BoolLiteral); 78 | //VISIT(DataLiteral); 79 | //VISIT(TextLiteral); 80 | //VISIT(ListLiteral); 81 | VISIT(Structure); 82 | 83 | #undef VISIT 84 | default: 85 | //rlog("Skipping node " << node->toString()); 86 | return true; 87 | } 88 | } 89 | 90 | bool visitStructure(ast::Structure *st) { 91 | bool hadUnknownBlockResultType = st->block()->resultType()->isUnknown(); 92 | 93 | if (!visitBlock(st->block())) 94 | return false; 95 | 96 | if (hadUnknownBlockResultType && st->block()->resultType()->isUnknown()) { 97 | return error(errs_ << "Failed to infer result type of block in struct"); 98 | } 99 | 100 | // Dependants might have been updated (deep structs), so we must update this 101 | // unconditionally. 102 | st->update(); 103 | 104 | return true; 105 | } 106 | 107 | bool visitFunction(ast::Function *fun, const Text& name = "__func") { 108 | DEBUG_TRACE_LFR_VISITOR; 109 | 110 | //if (fun->functionType()->resultTypeIsUnknown()) rlog("Unresolved function " << name); 111 | 112 | Scope scope(this); 113 | 114 | // Define a reference to ourselves 115 | defineSymbol(name, fun); 116 | 117 | // Define argument symbols 118 | FunctionType *FT = fun->functionType(); 119 | VariableList *args = FT->args(); 120 | for (ast::VariableList::const_iterator I = args->begin(), E = args->end(); I != E; ++I) { 121 | defineSymbol((*I)->name(), (*I)->type()); 122 | } 123 | 124 | if (!visitBlock(fun->body(), fun)) 125 | return false; 126 | 127 | // Materialize function type if neccessary 128 | if (FT->resultTypeIsUnknown() && !fun->body()->resultType()->isUnknown()) { 129 | FT->setResultType(fun->body()->resultType()); 130 | } 131 | 132 | return true; 133 | } 134 | 135 | 136 | // bool visitExternalFunction(ast::ExternalFunction *fun, const Text& name = "") { 137 | // DEBUG_TRACE_LFR_VISITOR; 138 | // Scope scope(this); 139 | 140 | // // Define a reference to ourselves 141 | // defineSymbol(name, fun); 142 | 143 | // return visitBlock(fun->body(), fun); 144 | // } 145 | 146 | 147 | bool visitBlock(ast::Block* block, ast::Function* parentFun = 0) { 148 | DEBUG_TRACE_LFR_VISITOR; 149 | Scope scope(this); 150 | 151 | ast::Expression* expression = 0; 152 | 153 | for (ExpressionList::const_iterator I = block->expressions().begin(), 154 | E = block->expressions().end(); 155 | I != E; ++I) 156 | { 157 | expression = *I; 158 | if (!visit(expression)) return false; 159 | } 160 | 161 | //rlog("block->resultType(): " << (block->resultType() ? block->resultType()->toString() : std::string("")) ); 162 | 163 | return true; 164 | } 165 | 166 | 167 | bool visitConditional(ast::Conditional* cond) { 168 | DEBUG_TRACE_LFR_VISITOR; 169 | 170 | if (cond->testExpression() == 0) return error(errs_ << "Missing test expression in conditional"); 171 | if (cond->trueBlock() == 0) return error(errs_ << "Missing true block in conditional"); 172 | if (cond->falseBlock() == 0) return error(errs_ << "Missing false block in conditional"); 173 | 174 | visit(cond->testExpression()); 175 | visitBlock(cond->trueBlock()); 176 | visitBlock(cond->falseBlock()); 177 | 178 | // If we know the result type, set the result type of any unresolved dependants 179 | const ast::Type* resultType = cond->resultType(); 180 | if (!resultType->isUnknown()) { 181 | //rlog("COND set " << resultType->toString()); 182 | cond->setResultType(resultType); 183 | } 184 | 185 | return true; 186 | } 187 | 188 | 189 | bool visitCall(ast::Call* call) { 190 | DEBUG_TRACE_LFR_VISITOR; 191 | const Target& target = lookupSymbol(*call->symbol()); 192 | 193 | if (target.isEmpty()) { 194 | return error(errs_ << "Unknown symbol \"" << call->symbol() << "\""); 195 | } 196 | 197 | // if (!target.hasValue()) { 198 | // return error(errs_ << "Trying to call \"" << call->symbol() 199 | // << "\" which is not a function (" 200 | // << (target.hasType() ? target.type->toString() : "?") << ")"); 201 | // } 202 | 203 | if (target.hasValue()) { 204 | if (!target.value->isCallable() && !target.value->isFunctionType()) { 205 | return error(errs_ << "Trying to call \"" << call->symbol() 206 | << "\" which is not a function (" << target.toString() << ")"); 207 | } 208 | call->setCalleeType(static_cast(target.value)->functionType()); 209 | 210 | } else if (target.hasType()) { 211 | if (!target.type->isFunction()) { 212 | return error(errs_ << "Trying to call \"" << call->symbol() 213 | << "\" which is not a function (" << target.toString() << ")"); 214 | } 215 | call->setCalleeType(static_cast(target.type)); 216 | 217 | } else { 218 | return error(errs_ << "Internal error: Symbol target is neither value nor type"); 219 | } 220 | 221 | //rlogw("visitCall(): found & resolved " << target.toString()); 222 | 223 | return true; 224 | } 225 | 226 | bool visitAssignment(ast::Assignment* node) { 227 | DEBUG_TRACE_LFR_VISITOR; 228 | const Text& name = node->variable()->name(); 229 | Expression* rhs = node->rhs(); 230 | 231 | defineSymbol(name, rhs); 232 | 233 | if (rhs->isFunction()) { 234 | ast::Function* F = static_cast(rhs); 235 | return visitFunction(F, name); 236 | //} else if (rhs->isExternalFunction()) { 237 | // ast::ExternalFunction* F = static_cast(rhs); 238 | // return visitExternalFunction(F, name); 239 | } else { 240 | return visit(node->rhs()); 241 | } 242 | } 243 | 244 | // Modifies symbol: setValue 245 | bool visitSymbol(ast::Symbol *sym) { 246 | DEBUG_TRACE_LFR_VISITOR; 247 | const Target& target = lookupSymbol(*sym); 248 | 249 | if (target.isEmpty()) { 250 | return error(errs_ << "Unknown symbol \"" << sym << "\""); 251 | 252 | } else { 253 | const ast::Type* T = target.resultType(); 254 | //rlog("Found target for " << sym->name() << ": " << (T ? T->toString() : std::string(""))); 255 | 256 | if (T != 0 && !T->isUnknown()) { 257 | sym->setResultType(T); 258 | assert(!sym->resultType()->isUnknown()); 259 | } 260 | } 261 | return true; 262 | } 263 | 264 | 265 | bool visitBinaryOp(ast::BinaryOp *binop) { 266 | DEBUG_TRACE_LFR_VISITOR; 267 | if (!visit(binop->lhs())) return false; 268 | return visit(binop->rhs()); 269 | } 270 | 271 | 272 | private: 273 | ast::Block* block_; 274 | std::ostringstream errs_; 275 | Scope* scope_; 276 | }; 277 | 278 | }} // namespace hue transform 279 | #endif // _HUE_TRANSFORM_LFR_TRANSFORMER_INCLUDED 280 | -------------------------------------------------------------------------------- /src/transform/Scope.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #include "Scope.h" 4 | #include "../Logger.h" 5 | 6 | namespace hue { namespace transform { 7 | 8 | Target Target::Empty; 9 | 10 | Scope::Scope(Scoped* supervisor) : supervisor_(supervisor) { 11 | supervisor_->scopeStack_.push_back(this); 12 | } 13 | Scope::~Scope() { 14 | supervisor_->scopeStack_.pop_back(); 15 | } 16 | 17 | 18 | const Target& Scoped::lookupSymbol(const Text& name) { 19 | // Scan symbol maps starting at top of stack moving down 20 | Scope::Stack::const_reverse_iterator I = scopeStack_.rbegin(); 21 | Scope::Stack::const_reverse_iterator E = scopeStack_.rend(); 22 | for (; I != E; ++I) { 23 | //Scope* scope = *I; 24 | const Target& target = (*I)->lookupSymbol(name); 25 | if (!target.isEmpty()) 26 | return target; 27 | } 28 | return Target::Empty; 29 | } 30 | 31 | 32 | const Target& Scoped::lookupSymbol(const ast::Symbol& sym) { 33 | const Text::List& pathname = sym.pathname(); 34 | assert(pathname.size() != 0); 35 | //rlog("pathname: " << Text("/").join(pathname)); 36 | 37 | // Lookup root 38 | const Target& target = lookupSymbol(pathname[0]); 39 | if (target.isEmpty() || pathname.size() == 1) { 40 | return target; 41 | } 42 | 43 | // Dig into target 44 | //rlog("digging into target 0: " << target.toString() << ", pathname: " << Text(", ").join(pathname)); 45 | return const_cast(target).lookupSymbol(pathname.begin()+1, pathname.end()); 46 | } 47 | 48 | 49 | const Target& Target::lookupSymbol(Text::List::const_iterator it, Text::List::const_iterator itend) { 50 | const Text& name = *it; 51 | ++it; 52 | //rlog("::lookupSymbol(\"" << name << "\", itend)"); 53 | 54 | Target* target = 0; 55 | 56 | // Already resolved? 57 | Target::Map::iterator MI = targets_.find(name); 58 | if (MI != targets_.end()) { 59 | target = &MI->second; 60 | 61 | } else { 62 | // Dig further based on our type 63 | const ast::Type* T = resultType(); 64 | if (T == 0) { 65 | return Target::Empty; 66 | } 67 | 68 | if (T->isFunction()) { 69 | Target& t = targets_[name]; 70 | t.typeID = FunctionType; 71 | if (it == itend) { 72 | t.type = T; 73 | } //else rlog("Target::lookupSymbol: Unexpected leaf when expecting a branch"); 74 | return t; 75 | 76 | } else if (!T->isStructure()) { 77 | Target& t = targets_[name]; 78 | t.typeID = LeafType; 79 | if (it == itend) { 80 | t.type = T; 81 | } //else rlog("Target::lookupSymbol: Unexpected leaf when expecting a branch"); 82 | return t; 83 | } 84 | 85 | // Else: T is a StructType 86 | const ast::StructType* ST = static_cast(T); 87 | 88 | // Lookup struct member by name 89 | const ast::Type* memberT = (*ST)[name]; 90 | if (memberT == 0) { 91 | rlogw("Unknown symbol \"" << name << "\" in struct " << ST->toString()); 92 | return Target::Empty; 93 | } 94 | //rloge("ST MEMBER for " << name << " => " << memberT->toString()); 95 | 96 | // Register target for name 97 | Target& t = targets_[name]; 98 | target = &t; 99 | if (memberT->isStructure()) { 100 | t.typeID = StructType; 101 | t.type = memberT; 102 | 103 | } else if (memberT->isFunction()) { 104 | t.typeID = FunctionType; 105 | if (it == itend) { 106 | t.type = memberT; 107 | } //else rlog("Target::lookupSymbol: Unexpected function leaf when expecting a branch"); 108 | 109 | } else { 110 | t.typeID = LeafType; 111 | if (it == itend) { 112 | t.type = memberT; 113 | } //else rlog("Target::lookupSymbol: Unexpected value leaf when expecting a branch"); 114 | } 115 | } 116 | 117 | // Are we the leaf? 118 | if (it == itend) { 119 | //rlog("Leaf found! -> " << (target ? target->toString() : std::string("")) ); 120 | return *target; 121 | } else { 122 | return target->lookupSymbol(it, itend); 123 | } 124 | } 125 | 126 | 127 | const ast::Type* Target::resultType() const { 128 | switch (typeID) { 129 | 130 | case ScopedValue: { 131 | if (value == 0) return 0; 132 | if (value->isExpression()) { 133 | const ast::Expression* expr = static_cast(value); 134 | return expr->resultType(); 135 | 136 | } else if (value->isValue()) { 137 | const ast::Value* var = static_cast(value); 138 | return var->resultType(); 139 | 140 | } else { 141 | return &ast::UnknownType; 142 | } 143 | } 144 | 145 | case LeafType: 146 | case StructType: 147 | case FunctionType: 148 | return type; 149 | 150 | default: return 0; 151 | } 152 | } 153 | 154 | 155 | std::string Target::toString() const { 156 | if (hasValue()) { 157 | return "value:" + (value ? 158 | (std::string(value->typeName()) + ":" + value->toString()) : std::string("")); 159 | } else if (hasType()) { 160 | return "type:" + (type ? type->toString() : std::string("")); 161 | } else { 162 | return ""; 163 | } 164 | } 165 | 166 | 167 | }} // namespace hue transform 168 | -------------------------------------------------------------------------------- /src/transform/Scope.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Rasmus Andersson. All rights reserved. Use of this source 2 | // code is governed by a MIT-style license that can be found in the LICENSE file. 3 | #ifndef _HUE_TRANSFORM_SCOPE_INCLUDED 4 | #define _HUE_TRANSFORM_SCOPE_INCLUDED 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // 17 | // Logic to deal with symbolic references, potentially nested in scopes. 18 | // 19 | 20 | namespace hue { namespace transform { 21 | 22 | class Scope; 23 | class Scoped; 24 | 25 | 26 | class Target { 27 | public: 28 | typedef std::map Map; 29 | 30 | static Target Empty; 31 | 32 | enum TargetType { 33 | ScopedValue = 0, 34 | LeafType, 35 | StructType, 36 | FunctionType, 37 | } typeID; 38 | 39 | //union { 40 | ast::Node* value; // typeID: ScopedValue 41 | const ast::Type* type; // typeID: StructType or FunctionType or LeafType 42 | //}; 43 | Scope* scope; // typeID: ScopedValue (else null) 44 | 45 | Target(TargetType typ = ScopedValue) : typeID(typ), value(0), type(0), scope(0) {} 46 | 47 | inline bool isEmpty() const { return value == 0 && type == 0; } 48 | inline bool hasValue() const { return typeID == ScopedValue; } 49 | inline bool hasType() const { 50 | return typeID == StructType || typeID == FunctionType || typeID == LeafType; } 51 | const ast::Type* resultType() const; 52 | 53 | // Find a sub-target 54 | const Target& lookupSymbol(Text::List::const_iterator it, Text::List::const_iterator itend); 55 | 56 | std::string toString() const; 57 | 58 | protected: 59 | Map targets_; 60 | }; 61 | 62 | 63 | // This class adds itself to the top of the stack of a supervisor Scoped 64 | // instance when created with a constructor that takes a Scoped instance. 65 | // When a Scope instance is deallocated, is pops itself from any Scoped's 66 | // stack is lives in. This makes it convenient to map stack scopes to Scope 67 | // instances: 68 | // 69 | // void parseBlock(Block* block) { 70 | // Scope scope(scopes_); // pushes itself to scopes_ stack 71 | // for each symboldef: 72 | // scope.defineSymbol(symboldef.name, symboldef.rhs); 73 | // // any code inside here can now access these symbols through 74 | // // scopes_.lookupSymbol(...). 75 | // } 76 | // // scope pops itself from scopes_ stack 77 | // 78 | class Scope { 79 | public: 80 | typedef std::deque Stack; 81 | 82 | Scope(Scoped* supervisor); 83 | virtual ~Scope(); 84 | 85 | // Define a symbol as being rooted in this scope. 86 | // *name* must not be a pathname. 87 | void defineSymbol(const Text& name, ast::Node *value) { 88 | Target& target = targets_[name]; 89 | target.value = value; 90 | target.scope = this; 91 | } 92 | 93 | void defineSymbol(const Text& name, const ast::Type *T) { 94 | Target& target = targets_[name]; 95 | target.value = new ast::Value(T); 96 | target.scope = this; 97 | } 98 | 99 | // Look up a target only in this scope. 100 | // Use Visitor::lookupSymbol to lookup stuff in any scope 101 | const Target& lookupSymbol(const Text& name) { 102 | Target::Map::const_iterator it = targets_.find(name); 103 | if (it != targets_.end()) { 104 | return it->second; 105 | } 106 | return Target::Empty; 107 | } 108 | 109 | protected: 110 | friend class Scoped; 111 | Scoped* supervisor_; 112 | Target::Map targets_; 113 | }; 114 | 115 | 116 | class Scoped { 117 | public: 118 | // Current scope, or 0 if none 119 | virtual Scope* currentScope() const { return scopeStack_.empty() ? 0 : scopeStack_.back(); } 120 | virtual Scope* parentScope() const { return scopeStack_.size() > 1 ? 0 : scopeStack_.back() -1; } 121 | virtual Scope* rootScope() const { return scopeStack_.size() == 0 ? 0 : scopeStack_.front(); } 122 | 123 | // Find a target by name 124 | const Target& lookupSymbol(const Text& name); 125 | 126 | // Find a target by a potentially nested symbol 127 | const Target& lookupSymbol(const ast::Symbol& sym); 128 | 129 | inline void defineSymbol(const Text& name, ast::Node *value) { 130 | currentScope()->defineSymbol(name, value); 131 | } 132 | inline void defineSymbol(const Text& name, const ast::Type *T) { 133 | currentScope()->defineSymbol(name, T); 134 | } 135 | 136 | private: 137 | friend class Scope; 138 | Scope::Stack scopeStack_; 139 | }; 140 | 141 | 142 | }} // namespace hue transform 143 | #endif // _HUE_TRANSFORM_SCOPE_INCLUDED 144 | -------------------------------------------------------------------------------- /src/utf8/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2006 Nemanja Trifunovic 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /test/test_factorial.hue: -------------------------------------------------------------------------------- 1 | # A classic recursive function, calculating the factorial of a natural number. 2 | # When compiled with optimizations, this will be unrolled into a very efficient 3 | # tail recursive call (in LLVM 3.0, this is only true for the integer version.) 4 | 5 | factorial = func (n Int) if n == 0 1 else n * factorial n - 1 6 | factorial = func (n Float) if n == 0 1 else n * factorial n - 1 7 | 8 | # Import print functions 9 | print = extern _ZN3hue12stdout_writeEx (v Int) 10 | print = extern _ZN3hue12stdout_writeEd (v Float) 11 | print = extern _ZN3hue12stdout_writeEPNS_6TextS_E (v [Char]) 12 | 13 | # Calulate factorials 14 | print (factorial 10) 15 | print " " 16 | print (factorial 10.0) 17 | print "\n" 18 | #>> 3628800 3628800.0 19 | 20 | # Alternative ways of structuring the function's code: 21 | # 22 | # a. Being more explicit about execution order: 23 | # factorial = func (n Int) 24 | # if (n == 0) 1 else (n * (factorial n - 1)) 25 | # 26 | # b. Utilizing multiple lines for readability 27 | # factorial = func (n Int) 28 | # if n == 0 29 | # 1 30 | # else 31 | # n * factorial n - 1 32 | # -------------------------------------------------------------------------------- /test/test_func_fib.hue: -------------------------------------------------------------------------------- 1 | # Here we test two things: 2 | # 3 | # 1. Recursive function result type inference (infer the result type 4 | # for a function that is used by itself) 5 | # 6 | # 2. The implementation of the classic recursive fib function. 7 | # 8 | 9 | print = extern _ZN3hue12stdout_writeEx (v Int) 10 | 11 | fib = func (n Int) 12 | if n < 2 13 | n 14 | else 15 | (fib n-1) + (fib n-2) 16 | 17 | print (fib 32) # -> 2178309 18 | -------------------------------------------------------------------------------- /test/test_func_inferred_result_type.hue: -------------------------------------------------------------------------------- 1 | foo = func (a Float) a * 9 2 | foo = func (a, b Int) a * b 3 | foo = func (a, b Int) 1.0 * a * b 4 | 5 | print = extern _ZN3hue12stdout_writeEx (v Int) 6 | print = extern _ZN3hue12stdout_writeEd (v Float) 7 | print = extern _ZN3hue12stdout_writeEPNS_6TextS_E (v [Char]) 8 | 9 | print (x1 = foo 5.1) 10 | print " " 11 | print (x2 Int = foo 1 2) 12 | print " " 13 | print (x3 Float = foo 1 2) 14 | print "\n" 15 | -------------------------------------------------------------------------------- /test/test_lang_bools.hue: -------------------------------------------------------------------------------- 1 | # Boolean values and type 2 | print = extern _ZN3hue12stdout_writeEb (v Bool) 3 | 4 | a = true 5 | b Bool = false # This will generate a harmless warning 6 | boolsAreEq = func (a, b Bool) a == b 7 | e = boolsAreEq a b 8 | 9 | print e # Should write "false" to stdout 10 | -------------------------------------------------------------------------------- /test/test_lang_conditionals.hue: -------------------------------------------------------------------------------- 1 | # Conditional = 'if' TestExpr TrueExpr 'else' FalseExpr 2 | x = if 1 3 | y = if 2 4 | 200 5 | else 6 | 300 7 | y + 1000 8 | else 9 | 300 10 | 11 | x2 = if 1 100 else 200 12 | 13 | x3 = if 1 14 | 100 15 | else if 2 16 | 200 17 | else 18 | 300 19 | -------------------------------------------------------------------------------- /test/test_lang_data_literals.hue: -------------------------------------------------------------------------------- 1 | print = extern _ZN3hue12stdout_writeEPNS_6DataS_E (data [Byte]) 2 | print = extern _ZN3hue12stdout_writeEPNS_6TextS_E (text [Char]) 3 | 4 | data1 = 'Hello World\n' # is Data 5 | text1 = "Hello World\n" # is Text 6 | print data1 7 | print text1 8 | -------------------------------------------------------------------------------- /test/test_lang_funcs.hue: -------------------------------------------------------------------------------- 1 | # 2 | # This test makes sure that function invariants works properly. 3 | # 4 | # A function can have multiple implementations where each implementation 5 | # must have a unique set of argument types (count + types). 6 | # 7 | 8 | foo = func (a Float) a 9 | foo = func (a Int) a 10 | foo = func (a, b Int) a * b 11 | foo = func (a, b Int) 1.0 * a * b 12 | foo = func (a, b Float) a * b 13 | 14 | #foo = func (a Int -> Int a # error "Implementation has already been defined for the symbol" 15 | #foo = 4 # error "Symbol has already been defined" 16 | #x = foo 2 3 4 # error "No function matching call to foo" 17 | #x = foo 2 3 # error "No function with result matching call to foo" 18 | 19 | x1 = foo 2.0 # foo -> ^(a Float Float 20 | x2 = foo 1 # foo -> ^(a Int Int 21 | x3 = foo 4.0 5.0 # foo -> ^(a, b Float Float 22 | x4 Int = foo 2 3 # foo -> ^(a, b Int Int 23 | x5 Float = foo 2 3 # foo -> ^(a, b Int Float 24 | 25 | print = extern _ZN3hue12stdout_writeEPNS_6DataS_E (v [Byte]) 26 | print = extern _ZN3hue12stdout_writeEPNS_6TextS_E (v [Char]) 27 | print = extern _ZN3hue12stdout_writeEb (v Bool) 28 | print = extern _ZN3hue12stdout_writeEd (v Float) 29 | print = extern _ZN3hue12stdout_writeEh (v Byte) 30 | print = extern _ZN3hue12stdout_writeEj (v Char) 31 | print = extern _ZN3hue12stdout_writeEx (v Int) 32 | 33 | data1 = 'Hello World\n' # T = [Byte] 34 | text1 = "Hello World\n" # T = [Char] 35 | print data1 36 | print text1 37 | 38 | (print "x1 => ") (print x1) print "\n" 39 | (print "x2 => ") (print x2) print "\n" 40 | (print "x1 == x2 => ") (print x1 == x2) print "\n" 41 | 42 | -------------------------------------------------------------------------------- /test/test_mangle.cc: -------------------------------------------------------------------------------- 1 | #include "../src/Mangle.h" 2 | #include "../src/ast/Type.h" 3 | #include "../src/ast/Variable.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using std::cout; 10 | using std::endl; 11 | using namespace hue; 12 | 13 | int main() { 14 | ast::Type NamedT("Foo"); 15 | ast::Type FloatT(ast::Type::Float); 16 | ast::Type IntT(ast::Type::Int); 17 | ast::Type CharT(ast::Type::Char); 18 | ast::Type ByteT(ast::Type::Byte); 19 | ast::Type BoolT(ast::Type::Bool); 20 | ast::Type FuncT(ast::Type::Func); 21 | 22 | // Verify Type -> Mangled id 23 | assert(hue::mangle(NamedT) == "N3Foo"); 24 | assert(hue::mangle(FloatT) == "F"); 25 | assert(hue::mangle(IntT) == "I"); 26 | assert(hue::mangle(CharT) == "C"); 27 | assert(hue::mangle(ByteT) == "B"); 28 | assert(hue::mangle(BoolT) == "b"); 29 | assert(hue::mangle(FuncT) == "f"); 30 | 31 | // Verify TypeList -> Mangled 32 | ast::TypeList types; 33 | types.push_back(&NamedT); 34 | types.push_back(&FloatT); 35 | types.push_back(&IntT); 36 | types.push_back(&CharT); 37 | types.push_back(&ByteT); 38 | types.push_back(&BoolT); 39 | types.push_back(&FuncT); 40 | assert(hue::mangle(types) == "N3FooFICBbf"); 41 | 42 | // Verify VariableList -> Mangled 43 | ast::VariableList vars; 44 | vars.push_back(new ast::Variable(&IntT)); 45 | vars.push_back(new ast::Variable(&IntT)); 46 | vars.push_back(new ast::Variable(&FloatT)); 47 | assert(hue::mangle(vars) == "IIF"); 48 | 49 | // Verify ^(a,b Int) Int -> Mangled 50 | types.clear(); 51 | types.push_back(&IntT); 52 | ast::FunctionType funcT1(&vars, &types); 53 | assert(hue::mangle(funcT1) == "$IIF$I"); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /test/test_object.cc: -------------------------------------------------------------------------------- 1 | // clang++ -std=c++11 -Wall -g -o co_object_test experiments/co_object_test.cc && ./co_object_test 2 | // 3 | // #include 4 | // #include 5 | // #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | using std::cerr; 21 | using std::endl; 22 | using namespace hue; 23 | 24 | static size_t live_toy_count = 0; 25 | static size_t live_cat_count = 0; 26 | 27 | class Toy { HUE_OBJECT(Toy) 28 | public: 29 | int bar; 30 | bool baz; 31 | 32 | static Toy* create(int bar, bool baz) { 33 | Toy* obj = __alloc(); 34 | obj->bar = bar; 35 | obj->baz = baz; 36 | __sync_add_and_fetch(&live_toy_count, 1); 37 | return obj; 38 | } 39 | 40 | void dealloc() { 41 | __sync_sub_and_fetch(&live_toy_count, 1); 42 | } 43 | 44 | inline Ref refcount() const { return __sync_fetch_and_add(&refcount_, 0); } 45 | }; 46 | 47 | class Cat { HUE_OBJECT(Cat) 48 | public: 49 | int age; 50 | char* name; 51 | Toy* toy; 52 | 53 | static Cat* create(int age, const char* name, Toy* toy) { 54 | Cat* obj = __alloc(); 55 | obj->age = age; 56 | obj->name = name ? strdup(name) : 0; 57 | obj->toy = toy ? toy->retain() : 0; 58 | __sync_add_and_fetch(&live_cat_count, 1); 59 | return obj; 60 | } 61 | 62 | void dealloc() { 63 | if (name) free(name); 64 | if (toy) toy->release(); 65 | __sync_sub_and_fetch(&live_cat_count, 1); 66 | } 67 | 68 | inline Ref refcount() const { return __sync_fetch_and_add(&refcount_, 0); } 69 | }; 70 | 71 | 72 | int main() { 73 | //HeapProfilerStart("main"); 74 | //ProfilerStart("main.prof"); 75 | 76 | uint64_t i = 0; 77 | uint64_t N = 10000; 78 | 79 | for (; i < N; ++i) { 80 | Toy* toy = Toy::create(i, i % 2 == 0 ); 81 | 82 | assert(live_cat_count == 0); 83 | assert(live_toy_count == 1); 84 | assert(toy->refcount() == 1); 85 | 86 | Cat* cat = Cat::create(4, "Zelda", toy); 87 | 88 | assert(live_cat_count == 1); 89 | assert(live_toy_count == 1); 90 | assert(cat->refcount() == 1); 91 | assert(cat->toy == toy); 92 | assert(cat->toy->refcount() == 2); 93 | 94 | toy->release(); 95 | 96 | assert(live_toy_count == 1); 97 | assert(cat->toy->refcount() == 1); 98 | 99 | cat->release(); 100 | 101 | assert(live_toy_count == 0); 102 | assert(live_cat_count == 0); 103 | } 104 | 105 | //ProfilerStop(); 106 | //HeapProfilerStop(); 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /test/test_struct.hue: -------------------------------------------------------------------------------- 1 | bar = struct # constant <{ i64, %type.S1d* }> 2 | a = 1 3 | b = struct # constant <{ double }> 4 | c = 2.3 5 | 6 | foo = func (n Int) 7 | struct # allocates <{ %type.S1x* }> 8 | x = struct # allocates <{ i64 }> 9 | y = n 10 | 11 | baz = func (n Int) 12 | y = n * 2 13 | struct bob = y # allocates <{ i64 }> 14 | 15 | Math = struct 16 | factorial = func (n Int) if n == 0 1 else n * factorial n - 1 17 | 18 | # Access into constant structs 19 | bar:a # 1 20 | bar:b:c # 2.3 21 | 22 | # Access into dynamic structs 23 | st1 = baz 20 # <{ i64 }> 24 | st1:bob # 40 25 | st2 = foo 123 # <{ <{ i64 }>* }> 26 | st2:x:y # 123 27 | 28 | # Func calls from struct traversal. 29 | # Implementation status: 30 | # - Parser: Complete 31 | # - Codegen: Incomplete (work pending in Visitor::lookupFunctionSymbols et al) 32 | #Math:factorial 4 33 | 34 | # Indirect member access 35 | # Implementation status: 36 | # - Parser: Incomplete 37 | # - Codegen: Incomplete 38 | #(foo 123):x:y 39 | 40 | # TODO: Prototypal inheritance. See https://gist.github.com/2893050 41 | -------------------------------------------------------------------------------- /test/test_vector.cc: -------------------------------------------------------------------------------- 1 | #define DEBUG_Node_refcount 2 | #define DEBUG_Vector_refcount 3 | #include "../src/runtime/Vector.h" 4 | 5 | using std::cerr; 6 | using std::endl; 7 | using namespace hue; 8 | 9 | int main() { 10 | // This test starts with an empty vector, appends 1 000 000 values using 11 | // single operations, and finally confirms the values by accessing each item. 12 | 13 | Vector* v = Vector::Empty; 14 | 15 | uint64_t i = 0; 16 | uint64_t N = 1000000; // 1M includes 2 root overflows 17 | 18 | for (; i < N; ++i) { 19 | Vector* oldV = v; 20 | v = v->append((void*)(i * 10)); 21 | oldV->release(); 22 | } 23 | 24 | //cerr << "count(): " << v->count() << endl; 25 | assert(v->count() == N); 26 | 27 | for (i = 0; i < N; ++i) { 28 | uint64_t _ = (uint64_t)v->itemAt(i); 29 | if (_ != (uint64_t)(i * 10)) { 30 | cerr << "itemAt returned incorrect value -- got " << _ 31 | << " but expected " << (uint64_t)(i * 10) << endl; 32 | } 33 | assert(_ == (uint64_t)(i * 10)); 34 | } 35 | 36 | // Release the vector 37 | ((Vector*)v)->release(); 38 | v = 0; 39 | 40 | // Verify that there are no leaks 41 | #ifdef DEBUG_LIVECOUNT_Node 42 | //cerr << "livecount of Node: " << DEBUG_LIVECOUNT_Node << endl; 43 | assert(DEBUG_LIVECOUNT_Node == 0); 44 | #endif 45 | 46 | #ifdef DEBUG_LIVECOUNT_Vector 47 | //cerr << "livecount of Vector: " << DEBUG_LIVECOUNT_Vector << endl; 48 | assert(DEBUG_LIVECOUNT_Vector == 0); 49 | #endif 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /test/test_vector_perf.cc: -------------------------------------------------------------------------------- 1 | #include "../src/runtime/Vector.h" 2 | #include 3 | #include 4 | 5 | using std::cerr; 6 | using std::endl; 7 | using namespace hue; 8 | 9 | int main(int argc, char **argv) { 10 | // This test starts with an empty vector, appends N (argv[0] as int) values using 11 | // single operations, and finally confirms the values by accessing each item. 12 | 13 | Vector* v = Vector::Empty; 14 | 15 | uint64_t i = 0; 16 | uint64_t N = (argc > 1) ? atoll(argv[1]) : 1000000; 17 | 18 | clock_t start1 = clock(); 19 | 20 | for (; i < N; ++i) { 21 | Vector* oldV = v; 22 | v = v->append((void*)(i * 2)); 23 | oldV->release(); 24 | } 25 | 26 | double ms1 = ((double)(clock() - start1)) / CLOCKS_PER_SEC * 1000.0; 27 | cerr << "Inserting " << N << " values: " << ms1 << " ms (avg " << ((ms1 / N) * 1000000.0) << " ns/insert)" << endl; 28 | 29 | assert(v->count() == N); 30 | 31 | clock_t start2 = clock(); 32 | 33 | for (i = 0; i < N; ++i) { 34 | uint64_t _ = (uint64_t)v->itemAt(i); 35 | _ += 1; // avoid stripping 36 | } 37 | 38 | double ms2 = ((double)(clock() - start2)) / CLOCKS_PER_SEC * 1000.0; 39 | cerr << "Accessing all " << N << " values: " << ms2 << " ms (avg " << ((ms2 / N) * 1000000.0) << " ns/access)" << endl; 40 | 41 | // Release the vector 42 | ((Vector*)v)->release(); 43 | v = 0; 44 | 45 | return 0; 46 | } 47 | 48 | // 49 | // Numbers from "make test_vector_perf" on a 3.4 GHz Intel Core i7: 50 | // 51 | // clang++ -Wall -std=c++11 -fno-rtti -O3 -DNDEBUG -o test/test_vector_perf.img test/test_vector_perf.cc 52 | // ./test/test_vector_perf.img 100 53 | // Inserting 100 values: 0.028 ms (avg 280 ns/insert) 54 | // Accessing all 100 values: 0.001 ms (avg 10 ns/access) 55 | // ./test/test_vector_perf.img 100000 56 | // Inserting 100000 values: 20.567 ms (avg 205.67 ns/insert) 57 | // Accessing all 100000 values: 0.554 ms (avg 5.54 ns/access) 58 | // ./test/test_vector_perf.img 1000000 59 | // Inserting 1000000 values: 202.387 ms (avg 202.387 ns/insert) 60 | // Accessing all 1000000 values: 5.302 ms (avg 5.302 ns/access) 61 | // ./test/test_vector_perf.img 10000000 62 | // Inserting 10000000 values: 1999.92 ms (avg 199.993 ns/insert) 63 | // Accessing all 10000000 values: 62.378 ms (avg 6.2378 ns/access) 64 | // ./test/test_vector_perf.img 100000000 65 | // Inserting 100000000 values: 20013.7 ms (avg 200.137 ns/insert) 66 | // Accessing all 100000000 values: 705.795 ms (avg 7.05795 ns/access) 67 | // 68 | --------------------------------------------------------------------------------