├── .editorconfig
├── .gitignore
├── .gitmodules
├── .travis.yml
├── LICENSE
├── README.md
├── SPEC.md
├── bin
├── kou
└── kouc
├── examples
├── factorial.kou
└── index.html
├── package-lock.json
├── package.json
├── scripts
└── wabt.sh
├── src
├── codegen
│ ├── context.ts
│ └── index.ts
├── desugarer
│ └── index.ts
├── kou.ts
├── kouc.ts
├── lexer
│ ├── error.ts
│ ├── index.ts
│ └── token.ts
├── parser
│ ├── ast.ts
│ ├── error.ts
│ └── index.ts
├── report-error.ts
├── stdlib.ts
├── typechecker
│ ├── context.ts
│ ├── error.ts
│ └── index.ts
├── util.ts
└── wasm.ts
├── test
├── codegen.spec.ts
├── desugarer.spec.ts
├── index.ts
├── lexer.spec.ts
├── parser.spec.ts
└── typechecker.spec.ts
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 2
7 | indent_style = space
8 | insert_final_newline = true
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # Built result
61 | dist
62 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatashiro/kou/90d90fa7188d003197b18a7e10c97101e190b018/.gitmodules
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "lts/*"
4 | script:
5 | - npm run format:dry
6 | - npm run build
7 | - npm test
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-2018 Hyunje Jun
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # kou
2 |
3 | A minimal language compiled into wasm bytecode
4 |
5 | [](https://www.npmjs.com/package/kou)
6 | [](https://travis-ci.org/utatti/kou)
7 | [](https://github.com/prettier/prettier)
8 |
9 | ## Language specification
10 |
11 | Please refer to [SPEC.md](SPEC.md).
12 |
13 | ## Demonstration
14 |
15 | [](https://asciinema.org/a/tP2sldS271HxxsKwWJ2RJdTHL)
16 |
17 | ## Milestones
18 |
19 | - [x] Tokenizer
20 | - [x] Parser
21 | - [x] Desugarer
22 | - [x] Type checker
23 | - [x] Code generator for wasm
24 | - [x] Basic codegen
25 | - [x] Complex types and expressions
26 | - [ ] [Codegen for string](https://github.com/utatti/kou/issues/1)
27 | - [ ] Module system
28 | - [ ] JS interop
29 | - [ ] IO
30 | - [ ] Bootstrapping
31 |
32 | ## Install
33 |
34 | ``` shell
35 | npm i -g kou
36 | ```
37 |
38 | ## Usage
39 |
40 | Compile:
41 |
42 | ``` shell
43 | kouc hello.kou -o hello.wasm
44 |
45 | # For the detailed usage
46 | kouc --help
47 | ```
48 |
49 | Run in CLI:
50 |
51 | ``` shell
52 | kou hello.wasm
53 |
54 | # For the detailed usage
55 | kou --help
56 | ```
57 |
58 | ## Reference
59 |
60 | - [WebAssembly Specification](https://webassembly.github.io/spec/core/index.html)
61 | - [WebAssembly Reference Manual](https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md)
62 | - [The Go Programming Language Specification](https://golang.org/ref/spec)
63 |
64 | ## License
65 |
66 | [MIT](LICENSE)
67 |
--------------------------------------------------------------------------------
/SPEC.md:
--------------------------------------------------------------------------------
1 | # kou Language Specification
2 |
3 | * [Introduction](#introduction)
4 | * [Notation](#notation)
5 | * [Lexical elements](#lexical-elements)
6 | + [Punctuation](#punctuation)
7 | + [Operators](#operators)
8 | + [Keywords](#keywords)
9 | + [Literals](#literals)
10 | + [Identifier](#identifier)
11 | * [Types](#types)
12 | + [Primary types](#primary-types)
13 | + [Function type](#function-type)
14 | + [Tuple type](#tuple-type)
15 | + [Array type](#array-type)
16 | + [Void type](#void-type)
17 | * [Module](#module)
18 | + [Import](#import)
19 | * [Declaration](#declaration)
20 | * [Expressions](#expressions)
21 | + [LitExpr](#litexpr)
22 | + [IdentExpr](#identexpr)
23 | + [TupleExpr](#tupleexpr)
24 | + [ArrayExpr](#arrayexpr)
25 | + [CallExpr](#callexpr)
26 | + [IndexExpr](#indexexpr)
27 | + [FuncExpr](#funcexpr)
28 | + [CondExpr](#condexpr)
29 | + [LoopExpr](#loopexpr)
30 | + [NewExpr](#newexpr)
31 | * [Assignment](#assignment)
32 | * [Break](#break)
33 | * [Block](#block)
34 |
35 | ## Introduction
36 |
37 | This document is a language specification (yet informal) of the kou programming
38 | language.
39 |
40 | ## Notation
41 |
42 | The syntax is specified using Extended Backus-Naur Form (EBNF).
43 |
44 | ```
45 | | alternation
46 | () grouping
47 | [] option (0 or 1 times)
48 | {} repetition (0 to n times)
49 | ```
50 |
51 | Lower-case production names are used to identify lexical tokens. Non-terminals
52 | are in CamelCase. Lexical tokens are enclosed in double quotes "".
53 |
54 | ## Lexical elements
55 |
56 | ### Punctuation
57 |
58 | ```
59 | -> , ( ) [ ] { } : = ;
60 | ```
61 |
62 | ### Operators
63 |
64 | Unary:
65 |
66 | ```
67 | unary_op = "+" | "-" | "!" .
68 | ```
69 |
70 | Binary:
71 |
72 | ```
73 | binary_op = rel_op | add_op | mul_op | bool_op .
74 | rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" .
75 | add_op = "+" | "-" | "|" | "^" .
76 | mul_op = "*" | "/" | "%" | "&" .
77 | bool_op = "||" | "&&" .
78 | ```
79 |
80 | ### Keywords
81 |
82 | ```
83 | import as let fn if else for in new while break
84 | ```
85 |
86 | ### Literals
87 |
88 | Integer:
89 |
90 | ```
91 | decimal_digit = "0" … "9" .
92 | int_lit = decimal_digit { decimal_digit } .
93 | ```
94 |
95 | Float:
96 |
97 | ```
98 | decimals = decimal_digit { decimal_digit } .
99 | float_lit = decimals "." [ decimals ]
100 | | "." decimals
101 | ```
102 |
103 | Char:
104 |
105 | ```
106 | escaped_char = "\" ( "n" | "r" | "t" | "\" | "'" | """ ) .
107 | char = unicode_char | escaped_char .
108 | char_lit = "'" ( char ) "'"
109 | ```
110 |
111 | String:
112 |
113 | ```
114 | string_lit = """ { char } """ .
115 | ```
116 |
117 | Boolean:
118 |
119 | ```
120 | bool_lit = "true" | "false"
121 | ```
122 |
123 | ### Identifier
124 |
125 | ```
126 | lower_letter = "a" … "z" .
127 | letter = lower_letter | "_" .
128 | ident = letter { letter | decimal_digit } .
129 | ```
130 |
131 | ## Types
132 |
133 | ```
134 | Type = PrimType | FuncType | TupleType | ArrayType | VoidType .
135 | ```
136 |
137 | ### Primary types
138 |
139 | ```
140 | PrimType = "int" | "float" | "str" | "bool" | "char" .
141 | ```
142 |
143 | ### Function type
144 |
145 | ```
146 | FuncType = Type "->" Type .
147 | ```
148 |
149 | ### Tuple type
150 |
151 | ```
152 | TupleType = "(" [ Type { "," Type } ] ")" .
153 | ```
154 |
155 | Semantically, 1-tuple is the same with its inner type, or 1-tuple is desugared
156 | into its inner type.
157 |
158 | Related: [TupleExpr](#tupleexpr)
159 |
160 | ### Array type
161 |
162 | ```
163 | ArrayType = "[" Type "]" .
164 | ```
165 |
166 | Related: [ArrayExpr](#arrayexpr)
167 |
168 | ### Void type
169 |
170 | ```
171 | VoidType = "void" .
172 | ```
173 |
174 | Void type does not have a value. Any actual value in the type of `"void"`
175 | should result in a semantic error.
176 |
177 | ## Module
178 |
179 | Each file in kou is represented as a module.
180 |
181 | ```
182 | Module = { Import } { Decl } .
183 | ```
184 |
185 | ### Import
186 |
187 | ```
188 | Import = "import" ImportPath
189 | "(" ImportElem { "," ImportElem } ")" .
190 | ImportPath = string_lit .
191 | ImportElem = ident [ "as" ident ] .
192 | ```
193 |
194 | ## Declaration
195 |
196 | ```
197 | Decl = "let" ident [ ":" Type ] "=" Expr .
198 | ```
199 |
200 | ## Expressions
201 |
202 | ```
203 | Expr = PrimUnaryExpr | BinaryExpr .
204 | BinaryExpr = Expr binary_op Expr .
205 | PrimUnaryExpr = PrimExpr | UnaryExpr .
206 | UnaryExpr = unary_op PrimUnaryExpr
207 | PrimExpr = LitExpr
208 | | IdentExpr
209 | | TupleExpr
210 | | ArrayExpr
211 | | CallExpr
212 | | FuncExpr
213 | | CondExpr
214 | | LoopExpr
215 | | NewExpr.
216 | ```
217 |
218 | `Expr` stands for *Expression*.
219 |
220 | ### LitExpr
221 |
222 | The name stands for *Literal Expression*.
223 |
224 | ```
225 | LitExpr = int_lit | float_lit | string_lit | bool_lit | char_lit .
226 | ```
227 |
228 | ### IdentExpr
229 |
230 | The name stands for *Identifier Expression*.
231 |
232 | ```
233 | IdentExpr = ident .
234 | ```
235 |
236 | ### TupleExpr
237 |
238 | ```
239 | TupleExpr = "(" [ Expr { "," Expr } ] ")" .
240 | ```
241 |
242 | Semantically, 1-tuple is the same with its inner value, or 1-tuple is desugared
243 | into its inner value.
244 |
245 | Related: [Tuple type](#tuple-type)
246 |
247 | ### ArrayExpr
248 |
249 | ```
250 | ArrayExpr = "[" Expr { "," Expr } "]"
251 | ```
252 |
253 | Related: [Array type](#array-type)
254 |
255 | ### CallExpr
256 |
257 | ```
258 | CallExpr = PrimExpr TupleExpr .
259 | ```
260 |
261 | Related: [TupleExpr](#tupleexpr)
262 |
263 | ### IndexExpr
264 |
265 | ```
266 | IndexExpr = PrimExpr "[" Expr "]" .
267 | ```
268 |
269 | It can be used to retrieve an element from an array or a tuple.
270 |
271 | For the tuple case, the index should be a `LitExpr` having `int_lit`, with a
272 | value in the tuple's size range.
273 |
274 | Related: [Literals](#literals)
275 |
276 | ### FuncExpr
277 |
278 | ```
279 | FuncExpr = "fn" ParamTuple Type Block .
280 | ParamTuple = "(" [ Param { "," Param } ] ")" .
281 | Param = ident Type .
282 | ```
283 |
284 | Related: [Block](#block)
285 |
286 | ### CondExpr
287 |
288 | ```
289 | CondExpr = "if" Expr Block "else" Block .
290 | ```
291 |
292 | Related: [Block](#block)
293 |
294 | ### LoopExpr
295 |
296 | ```
297 | LoopExpr = "while" Expr Block .
298 | ```
299 |
300 | Related:
301 |
302 | - [Block](#block)
303 | - [Break](#break)
304 |
305 | ### NewExpr
306 |
307 | ```
308 | NewExpr = "new" Type "[" Expr "]" .
309 | ```
310 |
311 | It creates an array with a specified size.
312 |
313 | Related:
314 |
315 | - [Array type](#array-type)
316 | - [ArrayExpr](#arrayexpr)
317 |
318 | ## Assignment
319 |
320 | ```
321 | Assign = LVal "=" Expr .
322 | ```
323 |
324 | ### LVal
325 |
326 | ```
327 | LVal = IdentExpr
328 | | IndexExpr .
329 | ```
330 |
331 | Related:
332 |
333 | - [IdentExpr](#identexpr)
334 | - [IndexExpr](#indexexpr)
335 |
336 | ## Break
337 |
338 | ```
339 | Break = "break" .
340 | ```
341 |
342 | Break only works in LoopExpr.
343 |
344 | Related: [LoopExpr](#loopexpr)
345 |
346 | ## Block
347 |
348 | ```
349 | Block = "{" { ( Expr | Decl | Assign | Break ) ";" } [ Expr ] "}" .
350 | ```
351 |
352 | A block ending without `Expr` (no `";"`) has its return type as `void`, and it
353 | is the only way to express `void` type in kou.
354 |
355 | Related: [Void type](#void-type)
356 |
--------------------------------------------------------------------------------
/bin/kou:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | require('../dist/kou');
3 |
--------------------------------------------------------------------------------
/bin/kouc:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | require('../dist/kouc');
3 |
--------------------------------------------------------------------------------
/examples/factorial.kou:
--------------------------------------------------------------------------------
1 | let fac = fn (n int) int {
2 | if (n == 1) {
3 | 1
4 | } else {
5 | n * fac(n - 1)
6 | }
7 | }
8 |
9 | let main = fn () int {
10 | fac(10)
11 | }
12 |
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | kou
5 |
6 |
12 |
13 |
14 | kou
15 |
16 | Upload *.wasm
17 |
18 | ()
19 |
20 |
21 | Result
22 |
23 |
24 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kou",
3 | "version": "0.3.0",
4 | "description": "A minimal language compiled into wasm bytecode",
5 | "main": "dist/kouc",
6 | "bin": {
7 | "kou": "bin/kou",
8 | "kouc": "bin/kouc"
9 | },
10 | "scripts": {
11 | "build": "tsc",
12 | "prettier": "prettier --parser typescript --single-quote --trailing-comma all '{src,test}/**/*.ts'",
13 | "format": "npm run prettier -- --write",
14 | "format:dry": "npm run prettier -- -l",
15 | "test": "ts-node --no-cache --type-check test",
16 | "release": "npm run build && npm publish"
17 | },
18 | "husky": {
19 | "hooks": {
20 | "pre-commit": "npm run format:dry",
21 | "pre-push": "npm run format:dry && npm run build && npm test"
22 | }
23 | },
24 | "repository": {
25 | "type": "git",
26 | "url": "git+https://github.com/utatti/kou.git"
27 | },
28 | "author": "Hyunjae Jun ",
29 | "license": "MIT",
30 | "bugs": {
31 | "url": "https://github.com/utatti/kou/issues"
32 | },
33 | "homepage": "https://github.com/utatti/kou",
34 | "devDependencies": {
35 | "husky": "^2.2.0",
36 | "prettier": "1.15.2",
37 | "ts-node": "7.0.1",
38 | "typescript": "3.1.6"
39 | },
40 | "dependencies": {
41 | "@types/node": "10.12.6",
42 | "@types/tmp": "0.0.33",
43 | "@types/webassembly-js-api": "0.0.1",
44 | "@types/yargs": "12.0.1",
45 | "chalk": "2.4.1",
46 | "hexy": "0.2.11",
47 | "previewable-iterator": "0.1.1",
48 | "s-exify": "^0.1.0",
49 | "wabt": "^1.0.10",
50 | "yargs": "12.0.2"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/scripts/wabt.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | git clone --branch 1.0.10 --depth 1 https://github.com/WebAssembly/wabt.git
3 | cd wabt
4 | git submodule update --init
5 | make gcc-release
6 |
--------------------------------------------------------------------------------
/src/codegen/context.ts:
--------------------------------------------------------------------------------
1 | import * as a from '../parser/ast';
2 | import { StdFunc, defaultStdFuncs } from '../stdlib';
3 |
4 | export class CodegenContext {
5 | private globalNameMap: Map = new Map();
6 | private localNameMaps: Array