├── .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