├── .gitignore ├── README.md ├── index.html ├── package.json └── src └── main.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Tsoding](https://img.shields.io/badge/twitch.tv-tsoding-purple?logo=twitch&style=for-the-badge)](https://www.twitch.tv/tsoding) 2 | # CykaScript 3 | 4 | ## Quick Start 5 | 6 | ```console 7 | $ npm install 8 | $ npm run build 9 | $ browser index.html 10 | ``` 11 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | My First Programming Language 4 | 5 | 6 |
7 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescripto", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "tsc --lib es6 src/main.ts" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "typescript": "^2.8.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | class Context { 2 | defineVar(name: string, value: number): void { 3 | this._nameTable.set(name, value) 4 | } 5 | 6 | varValue(name: string): number { 7 | return this._nameTable.get(name); 8 | } 9 | 10 | print(value: number): void { 11 | this._log.push(value + "") 12 | } 13 | 14 | stdout(): Array { 15 | return this._log; 16 | } 17 | 18 | pushScope(): void { 19 | } 20 | 21 | popScope(): void { 22 | } 23 | 24 | private _log = new Array(); 25 | private _nameTable = new Map(); 26 | } 27 | 28 | interface AstNode { 29 | eval(context: Context): T 30 | } 31 | 32 | class For implements AstNode { 33 | constructor(private _lower: AstNode, 34 | private _upper: AstNode, 35 | private _iter: string, 36 | private _body: AstNode) { 37 | } 38 | 39 | eval(context: Context) { 40 | let lower = this._lower.eval(context); 41 | let upper = this._upper.eval(context); 42 | 43 | context.pushScope(); 44 | context.defineVar(this._iter, lower); 45 | for (let i = lower; i <= upper; ++i) { 46 | context.defineVar(this._iter, i); 47 | this._body.eval(context); 48 | } 49 | context.popScope(); 50 | } 51 | } 52 | 53 | class Print implements AstNode { 54 | constructor(private _value: AstNode) { 55 | } 56 | 57 | eval(context: Context): void { 58 | context.print(this._value.eval(context)); 59 | } 60 | } 61 | 62 | class Block implements AstNode { 63 | constructor(private _statements: Array>) { 64 | } 65 | 66 | eval(context: Context): void { 67 | context.pushScope(); 68 | this._statements.forEach((statement) => { 69 | statement.eval(context) 70 | }) 71 | context.popScope(); 72 | } 73 | } 74 | 75 | class AssignVar implements AstNode { 76 | constructor(private _name: string, 77 | private _value: AstNode) { 78 | } 79 | 80 | eval(context: Context): void { 81 | context.defineVar(this._name, this._value.eval(context)); 82 | } 83 | } 84 | 85 | class Var implements AstNode { 86 | constructor(private _name: string) { 87 | } 88 | 89 | eval(context: Context): number { 90 | return context.varValue(this._name); 91 | } 92 | } 93 | 94 | class Plus implements AstNode { 95 | constructor(private _left: AstNode, 96 | private _right: AstNode) { 97 | } 98 | 99 | eval(context: Context): number { 100 | return this._left.eval(context) + this._right.eval(context); 101 | } 102 | } 103 | 104 | class Multiply implements AstNode { 105 | constructor(private _left: AstNode, 106 | private _right: AstNode) { 107 | } 108 | 109 | eval(context: Context): number { 110 | return this._left.eval(context) * this._right.eval(context); 111 | } 112 | } 113 | 114 | class NumberLiteral implements AstNode { 115 | constructor(private _value: number) { 116 | } 117 | 118 | eval(context: Context): number { 119 | return this._value 120 | } 121 | } 122 | 123 | let context = new Context() 124 | let program = new Block([ 125 | new AssignVar("x", new Plus( 126 | new NumberLiteral(5), 127 | new Multiply( 128 | new NumberLiteral(2), 129 | new NumberLiteral(10) 130 | ) 131 | )), 132 | new For(new NumberLiteral(1), 133 | new NumberLiteral(10), 134 | "i", 135 | new Block([ 136 | new AssignVar("x", new Plus( 137 | new Var("x"), 138 | new NumberLiteral(2) 139 | )), 140 | new Print(new Var("x")) 141 | ])) 142 | ]) 143 | 144 | program.eval(context); 145 | 146 | --------------------------------------------------------------------------------