├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── images ├── factorialweb.jpg ├── helloweb.jpg └── templateweb.png ├── lib ├── cobolscript.js ├── lexers.js └── parsers.js ├── package.json ├── samples ├── factorial │ ├── README.md │ ├── factorial.cob │ └── run.js ├── factorialweb │ ├── README.md │ ├── factorial.cob │ └── server.js ├── hello │ ├── README.md │ ├── compile.js │ ├── hello.cob │ ├── hello2.cob │ └── run.js ├── helloasync │ ├── README.md │ ├── hello.cob │ └── run.js ├── hellopgm │ ├── README.md │ ├── hello.cob │ └── run.js ├── helloweb │ ├── README.md │ ├── hello.cob │ └── server.js ├── linkage │ ├── README.md │ ├── hello.cob │ └── server.js ├── local │ ├── README.md │ ├── factorial.cob │ └── run.js ├── mysql │ ├── README.md │ ├── package.json │ ├── run.js │ └── showdb.cob ├── mysqlweb │ ├── README.md │ ├── database.cobp │ ├── databases.cobp │ ├── package.json │ ├── server.js │ └── table.cobp ├── template │ ├── README.md │ ├── factorial.cobt │ └── run.js ├── templateweb │ ├── README.md │ ├── factorial.cobp │ └── server.js ├── webserver │ ├── README.md │ ├── run.js │ └── webserver.cob └── website │ ├── README.md │ ├── database.sql │ ├── package.json │ ├── pages │ ├── customerDelete.cob │ ├── customerList.cobp │ ├── customerNew.cob │ ├── customerNew.cobp │ ├── customerUpdate.cob │ ├── customerUpdate.cobp │ ├── customerView.cobp │ ├── index.cobp │ ├── layout.cobp │ ├── supplierDelete.cob │ ├── supplierList.cobp │ ├── supplierNew.cob │ ├── supplierNew.cobp │ ├── supplierUpdate.cob │ ├── supplierUpdate.cobp │ └── supplierView.cobp │ ├── public │ └── css │ │ ├── bootstrap.css │ │ └── styles.css │ └── server.js ├── test.js └── test ├── add.js ├── compile.js ├── compileperform.js ├── files ├── hello.cob └── hello.cobt ├── if.js ├── lexers.js ├── move.js ├── parsers.js ├── perform.js ├── program.js ├── run.js ├── runtime.js ├── subtract.js ├── template.js └── ws.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /samples 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (C) 2012, 2013, Angel J Lopez 3 | http://www.ajlopez.com 4 | http://ajlopez.wordpress.com 5 | http://twitter.com/ajlopez 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajlopez/CobolScript/04a209d9c7986325fee354195ccc8b1b4e1c22d7/README.md -------------------------------------------------------------------------------- /images/factorialweb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajlopez/CobolScript/04a209d9c7986325fee354195ccc8b1b4e1c22d7/images/factorialweb.jpg -------------------------------------------------------------------------------- /images/helloweb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajlopez/CobolScript/04a209d9c7986325fee354195ccc8b1b4e1c22d7/images/helloweb.jpg -------------------------------------------------------------------------------- /images/templateweb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajlopez/CobolScript/04a209d9c7986325fee354195ccc8b1b4e1c22d7/images/templateweb.png -------------------------------------------------------------------------------- /lib/cobolscript.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var require; 5 | 6 | var parsers = require('./parsers'); 7 | 8 | var cobolscript = (function () { 9 | var fs = (typeof require === 'function') ? require('fs') : null; 10 | 11 | function compileTemplateText(text) { 12 | if (!text) 13 | return ''; 14 | 15 | text = text.replace(/\"/g, '\\"'); 16 | text = text.replace(/\n/g, '\\n'); 17 | text = text.replace(/\r/g, '\\r'); 18 | return '"' + text + '"'; 19 | }; 20 | 21 | function compileTemplateExpression(text) { 22 | var begin = text.indexOf("${"); 23 | 24 | if (begin < 0) 25 | return compileTemplateText(text); 26 | 27 | var rest = text.slice(begin + 2); 28 | var end = rest.indexOf("}"); 29 | 30 | if (begin >= 0 && end >= 0) { 31 | var left = text.slice(0, begin); 32 | var right = rest.slice(end + 1); 33 | 34 | var result = ''; 35 | 36 | if (left) 37 | result += compileTemplateText(left); 38 | 39 | result += ' ' + rest.slice(0, end); 40 | 41 | if (right) 42 | result += ' ' + compileTemplateExpression(right); 43 | 44 | return result; 45 | } 46 | 47 | return compileTemplateText(text); 48 | }; 49 | 50 | function compileTemplateToCode(text) { 51 | var begin = text.indexOf("<#"); 52 | var end = text.indexOf("#>"); 53 | 54 | if (begin >= 0 && end > begin) { 55 | var left = text.slice(0, begin); 56 | var right = text.slice(end + 2); 57 | 58 | if (right && right[0] == '\r') 59 | right = right.slice(1); 60 | if (right && right[0] == '\n') 61 | right = right.slice(1); 62 | 63 | var result = ''; 64 | 65 | if (left) 66 | result += 'display ' + compileTemplateExpression(left) + ' with no advancing'; 67 | 68 | result += text.slice(begin + 2, end); 69 | 70 | if (right) 71 | result += compileTemplateToCode(right); 72 | 73 | return result; 74 | } 75 | 76 | return 'display ' + compileTemplateExpression(text) + ' with no advancing'; 77 | }; 78 | 79 | function compileProgram(text, ws) { 80 | var parser = parsers.createParser(text); 81 | var program = parser.parseProgram(); 82 | 83 | if (ws) { 84 | program.data = program.data || { }; 85 | program.data.working_storage = ws; 86 | } 87 | 88 | program.procedure = program.compileFunction(); 89 | 90 | return program; 91 | }; 92 | 93 | function compileTemplate(text, ws) { 94 | var code = compileTemplateToCode(text); 95 | return compileProgram(code, ws); 96 | }; 97 | 98 | function Runtime() 99 | { 100 | this.buffer = ''; 101 | if (typeof global !== 'undefined') 102 | this.global = global; 103 | if (typeof window !== 'undefined') 104 | this.window = window; 105 | }; 106 | 107 | Runtime.prototype.display = function() { 108 | if (arguments && arguments.length) 109 | for (var k = 0; k < arguments.length; k++) 110 | if (arguments[k] != null) 111 | this.buffer += arguments[k].toString(); 112 | 113 | console.log(this.buffer); 114 | this.buffer = ''; 115 | }; 116 | 117 | Runtime.prototype.write = function() { 118 | if (arguments && arguments.length) 119 | for (var k = 0; k < arguments.length; k++) 120 | if (arguments[k] != null) 121 | this.buffer += arguments[k].toString(); 122 | }; 123 | 124 | Runtime.prototype.flush = function() { 125 | if (this.buffer) 126 | console.log(this.buffer); 127 | this.buffer = ''; 128 | }; 129 | 130 | Runtime.prototype.stop = function(value) { 131 | value = value || 0; 132 | this.flush(); 133 | process.exit(value); 134 | }; 135 | 136 | function getIndex(obj, index) { 137 | if (typeof index == 'number') 138 | return obj[index - 1]; 139 | return obj[index]; 140 | } 141 | 142 | function setIndex(obj, index, value) { 143 | if (typeof index == 'number') 144 | obj[index - 1] = value; 145 | else 146 | obj[index] = value; 147 | } 148 | 149 | Runtime.prototype.getIndex = getIndex; 150 | Runtime.prototype.setIndex = setIndex; 151 | 152 | function WebRuntime(request, response) 153 | { 154 | this.request = request; 155 | this.response = response; 156 | if (typeof global !== 'undefined') 157 | this.global = global; 158 | if (typeof window !== 'undefined') 159 | this.window = window; 160 | }; 161 | 162 | WebRuntime.prototype.display = function() { 163 | if (this.layout) { 164 | if (this.body == null) 165 | this.body = ''; 166 | if (arguments && arguments.length) 167 | for (var k = 0; k < arguments.length; k++) 168 | if (arguments[k] != null) 169 | this.body += arguments[k].toString(); 170 | 171 | this.body += '\r\n'; 172 | 173 | return; 174 | }; 175 | 176 | if (arguments && arguments.length) 177 | for (var k = 0; k < arguments.length; k++) 178 | if (arguments[k] != null) 179 | this.response.write(arguments[k].toString()); 180 | 181 | this.response.write('\r\n'); 182 | }; 183 | 184 | WebRuntime.prototype.write = function() { 185 | if (this.layout) { 186 | if (this.body == null) 187 | this.body = ''; 188 | if (arguments && arguments.length) 189 | for (var k = 0; k < arguments.length; k++) 190 | if (arguments[k] != null) 191 | this.body += arguments[k].toString(); 192 | 193 | return; 194 | }; 195 | 196 | if (arguments && arguments.length) 197 | for (var k = 0; k < arguments.length; k++) 198 | if (arguments[k]) 199 | this.response.write(arguments[k].toString()); 200 | }; 201 | 202 | WebRuntime.prototype.flush = function() { 203 | // TODO to be reviewed, other use cases 204 | if (this.layout) { 205 | var layout = this.layout; 206 | delete this.layout; 207 | layout.run(this); 208 | return; 209 | } 210 | 211 | this.response.end(); 212 | }; 213 | 214 | WebRuntime.prototype.stop = function(value) { 215 | this.flush(); 216 | }; 217 | 218 | WebRuntime.prototype.getIndex = getIndex; 219 | WebRuntime.prototype.setIndex = setIndex; 220 | 221 | function getRuntime(options) { 222 | var runtime; 223 | 224 | if (options && options.request && options.response) 225 | runtime = new WebRuntime(options.request, options.response); 226 | else 227 | runtime = new Runtime(); 228 | 229 | for (var n in options) 230 | runtime[n] = options[n]; 231 | 232 | return runtime; 233 | }; 234 | 235 | return { 236 | compileProgram: compileProgram, 237 | compileTemplate: compileTemplate, 238 | compileProgramFile: function(filename, noprocedure) { 239 | var text = fs.readFileSync(filename).toString(); 240 | return compileProgram(text, noprocedure); 241 | }, 242 | compileTemplateFile: function(filename, noprocedure) { 243 | var text = fs.readFileSync(filename).toString(); 244 | return compileTemplate(text, noprocedure); 245 | }, 246 | getRuntime: getRuntime 247 | }; 248 | })(); 249 | 250 | if (typeof window === 'undefined') { 251 | module.exports = cobolscript; 252 | } 253 | -------------------------------------------------------------------------------- /lib/lexers.js: -------------------------------------------------------------------------------- 1 | 2 | const TokenType = { Integer: 1, String: 2, Name: 3, Punctuation: 4, Operator: 5 }; 3 | 4 | const punctuations = ".,()"; 5 | const operators = [ ">", "<", "=", ">=", "<=", "<>" ]; 6 | 7 | function Token(value, type) { 8 | this.value = value; 9 | this.type = type; 10 | } 11 | 12 | function Lexer(text) { 13 | let position = 0; 14 | const nexts = []; 15 | 16 | function nextChar() { 17 | return text[position++]; 18 | } 19 | 20 | function pushChar(ch) { 21 | if (ch) { 22 | position--; 23 | } 24 | } 25 | 26 | function isSpace(ch) { 27 | if (ch <= ' ') { 28 | return true; 29 | } 30 | 31 | return false; 32 | } 33 | 34 | function isLetter(ch) { 35 | return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); 36 | } 37 | 38 | function isOperator(ch) { 39 | return operators.indexOf(ch) >= 0; 40 | } 41 | 42 | function isDigit(ch) { 43 | return ch && ch >= '0' && ch <= '9'; 44 | } 45 | 46 | function skipSpaces() { 47 | while (true) { 48 | while (position < text.length && isSpace(text[position])) { 49 | position++; 50 | } 51 | 52 | if (position < text.length && text[position] === '*') { 53 | while (position < text.length && text[position] !== '\r' && text[position] !== '\n') { 54 | position++; 55 | } 56 | } else { 57 | break; 58 | } 59 | } 60 | } 61 | 62 | function nextFirstChar() { 63 | if (!text) { 64 | return null; 65 | } 66 | 67 | skipSpaces(); 68 | 69 | if (position >= text.length) { 70 | return null; 71 | } 72 | 73 | return nextChar(); 74 | } 75 | 76 | function nextName(letter) { 77 | let name = letter; 78 | let ch; 79 | 80 | for (ch = nextChar(); ch && (isLetter(ch) || isDigit(ch) || ch === '-'); ch = nextChar()) { 81 | name += ch; 82 | } 83 | 84 | pushChar(ch); 85 | 86 | return new Token(name, TokenType.Name); 87 | } 88 | 89 | function nextOperator(letter) { 90 | const ch = nextChar(); 91 | const value = letter + ch; 92 | 93 | if (operators.indexOf(value) >= 0) 94 | return new Token(value, TokenType.Operator); 95 | 96 | pushChar(ch); 97 | 98 | return new Token(letter, TokenType.Operator); 99 | } 100 | 101 | function nextString() { 102 | let name = ''; 103 | let ch; 104 | 105 | for (ch = nextChar(); ch && ch !== '"'; ch = nextChar()) { 106 | name += ch; 107 | 108 | if (ch === '\\') { 109 | name += nextChar(); 110 | } 111 | } 112 | 113 | if (!ch) 114 | throw "unclosed string"; 115 | 116 | return new Token(name, TokenType.String); 117 | } 118 | 119 | function nextNumber(digit) { 120 | let number = digit; 121 | let ch; 122 | 123 | for (ch = nextChar(); ch && isDigit(ch); ch = nextChar()) { 124 | number += ch; 125 | } 126 | 127 | pushChar(ch); 128 | 129 | return new Token(number, TokenType.Integer); 130 | } 131 | 132 | this.nextPhrase = function () { 133 | let lastchar = null; 134 | let lastposition = null; 135 | const l = text.length; 136 | let initial; 137 | let ch; 138 | 139 | skipSpaces(); 140 | 141 | initial = position; 142 | 143 | while (position < l) { 144 | ch = text[position]; 145 | 146 | if (lastchar === '.' && (ch === '\r' || ch === '\n')) { 147 | return text.slice(initial, lastposition); 148 | } 149 | 150 | if (!isSpace(ch)) { 151 | lastchar = ch; 152 | lastposition = position; 153 | } 154 | 155 | position++; 156 | } 157 | 158 | if (lastchar === '.') 159 | return text.slice(initial, lastposition); 160 | 161 | throw "unexpected end of input"; 162 | } 163 | 164 | this.nextToken = function () { 165 | if (nexts.length > 0) 166 | return nexts.pop(); 167 | 168 | const ch = nextFirstChar(); 169 | 170 | if (ch === null) 171 | return null; 172 | 173 | if (isLetter(ch)) 174 | return nextName(ch); 175 | 176 | if (isDigit(ch)) 177 | return nextNumber(ch); 178 | 179 | if (isOperator(ch)) 180 | return nextOperator(ch); 181 | 182 | if (ch === '"') 183 | return nextString(); 184 | 185 | if (punctuations.indexOf(ch) >= 0) 186 | return new Token(ch, TokenType.Punctuation); 187 | 188 | throw "unexpected '" + ch + "'"; 189 | } 190 | 191 | this.pushToken = function(token) { 192 | if (token) 193 | nexts.push(token); 194 | } 195 | 196 | this.peekToken = function () { 197 | const token = this.nextToken(); 198 | 199 | if (token) 200 | this.pushToken(token); 201 | 202 | return token; 203 | } 204 | } 205 | 206 | function createLexer(text) { 207 | return new Lexer(text); 208 | } 209 | 210 | function createToken(value, type) { 211 | return new Token(value, type); 212 | } 213 | 214 | module.exports = { 215 | createLexer: createLexer, 216 | TokenType: TokenType, 217 | createToken: createToken 218 | } 219 | 220 | -------------------------------------------------------------------------------- /lib/parsers.js: -------------------------------------------------------------------------------- 1 | 2 | var lexers = require('./lexers'); 3 | var TokenType = lexers.TokenType; 4 | 5 | var verbs = [ 6 | "display", 7 | "add", "subtract", "multiply", "divide", 8 | "move", "perform", "compute", 9 | "if", "else", 10 | "return", 11 | "local", "locals", "global", "globals", 12 | "open", "close", "read", "write", 13 | "stop", "exit" 14 | ]; 15 | 16 | var reserved = [ 17 | "to", "from", "by", "into", 18 | "no", "with", 19 | "or", "and", 20 | "is", "not", "then", 21 | "async", "asynchronous", "error", 22 | "advancing", 23 | "giving", "using", 24 | "than", 25 | "until", 26 | "varying", 27 | "division", "section", 28 | "end_if", "end_perform", "end_read" 29 | ]; 30 | 31 | function StringExpression(text) 32 | { 33 | this.compile = function() { 34 | return '"' + text + '"'; 35 | }; 36 | } 37 | 38 | function IntegerExpression(text) 39 | { 40 | this.compile = function() { 41 | return text; 42 | }; 43 | } 44 | 45 | function BinaryExpression(left, oper, right) { 46 | if (oper === '=') { 47 | oper = '=='; 48 | } else if (oper === '<>') { 49 | oper = '!='; 50 | } 51 | 52 | this.compile = function(program, context) { 53 | return left.compile(program, context) + ' ' + oper + ' ' + right.compile(program, context); 54 | } 55 | } 56 | 57 | function IndexedVariableExpression(name, index) 58 | { 59 | var variable = new VariableExpression(name); 60 | 61 | this.compile = function(program, context) { 62 | var code = 'runtime.getIndex(' + variable.compile(program, context); 63 | code += ', '; 64 | code += index.compile(program, context); 65 | code += ')'; 66 | return code; 67 | } 68 | 69 | this.compileSet = function(program, context, value) { 70 | var code = 'runtime.setIndex(' + variable.compile(program, context); 71 | code += ', '; 72 | code += index.compile(program, context); 73 | code += ', '; 74 | code += value; 75 | code += ')'; 76 | return code; 77 | } 78 | } 79 | 80 | function VariableExpression(name) 81 | { 82 | name = normalizeName(name); 83 | 84 | this.compile = function(program, context) { 85 | if (name === 'object') 86 | return '{}'; 87 | 88 | if (name === 'array') 89 | return '[]'; 90 | 91 | if (context && context.arguments && typeof context.arguments[name] !== 'undefined') 92 | return name; 93 | 94 | if (context && context.locals && typeof context.locals[name] !== 'undefined') 95 | return name; 96 | 97 | if (program && program.procedures && typeof program.procedures[name] !== 'undefined') 98 | return name; 99 | 100 | if (program && program.data && program.data.linkage && typeof program.data.linkage[name] !== 'undefined') 101 | return 'runtime.' + name; 102 | 103 | if (program && program.data && program.data.working_storage) 104 | return compileWs('ws', program.data.working_storage); 105 | }; 106 | 107 | this.getName = function() { return name; }; 108 | 109 | function compileWs(prefix, items) { 110 | if (typeof items[name] !== 'undefined') { 111 | return prefix + "." + name; 112 | } 113 | 114 | for (var k in items) { 115 | if (!items[k]) { 116 | continue; 117 | } 118 | 119 | var newprefix = prefix + "." + k; 120 | 121 | var result = compileWs(newprefix, items[k]); 122 | 123 | if (result) { 124 | return result; 125 | } 126 | } 127 | }; 128 | }; 129 | 130 | function QualifiedVariableExpression(names) 131 | { 132 | var l = names.length; 133 | 134 | for (var k = 0; k < l; k++) { 135 | names[k] = normalizeName(names[k]); 136 | } 137 | 138 | var variable = new VariableExpression(names[0]); 139 | 140 | this.compile = function(program, context) { 141 | var name = variable.compile(program, context); 142 | return fullName(name); 143 | }; 144 | 145 | function fullName(name) { 146 | for (var k = 1; k < l; k++) { 147 | name += '.' + names[k]; 148 | } 149 | 150 | return name; 151 | }; 152 | 153 | this.getName = function() { return fullName(names[0]); }; 154 | }; 155 | 156 | function LocalCommand(names) 157 | { 158 | var n = names.length; 159 | 160 | this.compile = function(program, context) { 161 | var code = 'var '; 162 | 163 | if (!context.locals) { 164 | context.locals = {}; 165 | } 166 | 167 | for (var k = 0; k < n; k++) { 168 | if (k) 169 | code += ', '; 170 | var name = names[k]; 171 | context.locals[name] = null; 172 | code += name; 173 | } 174 | 175 | return code + ';'; 176 | }; 177 | }; 178 | 179 | function GlobalCommand(names) 180 | { 181 | var n = names.length; 182 | this.compile = function(program, context) { 183 | // TODO quick trick, declare as locals 184 | if (!context.locals) { 185 | context.locals = {}; 186 | } 187 | 188 | for (var k = 0; k < n; k++) { 189 | context.locals[names[k]] = null; 190 | } 191 | 192 | return ''; 193 | }; 194 | }; 195 | 196 | function IfCommand(cond, thencommands, elsecommands) 197 | { 198 | this.compile = function(program, context) { 199 | var code = 'if (' + cond.compile(program, context) + ') { ' + thencommands.compile(program, context) + ' }'; 200 | if (elsecommands) 201 | code += ' else { ' + elsecommands.compile(program, context) + ' }'; 202 | return code; 203 | }; 204 | }; 205 | 206 | function ReturnCommand(expr) { 207 | this.endsWithReturn = true; 208 | 209 | this.compile = function(program, context) { 210 | var codeexpr; 211 | 212 | if (expr) 213 | codeexpr = expr.compile(program, context); 214 | 215 | var code; 216 | 217 | if (context.async) { 218 | code = '$cb('; 219 | if (expr) 220 | code += codeexpr; 221 | code += '); return'; 222 | } 223 | else { 224 | code = 'return'; 225 | 226 | if (expr) 227 | code += ' ' + codeexpr; 228 | } 229 | 230 | code += ';'; 231 | return code; 232 | }; 233 | }; 234 | 235 | function ProcedureCommand(name, commands, args, options) 236 | { 237 | name = normalizeName(name); 238 | options = options || { }; 239 | 240 | this.compile = function(program, context) { 241 | var code = 'function ' + name + '('; 242 | code += compileArguments(); 243 | code += ') { '; 244 | 245 | var newcontext = getContext(context); 246 | 247 | if (commands) 248 | code += commands.compile(program, newcontext); 249 | 250 | if (options.async) { 251 | if (!(commands && commands.endsWithReturn)) 252 | code += (new ReturnCommand()).compile(program, newcontext); 253 | } 254 | 255 | code += ' }'; 256 | return code; 257 | }; 258 | 259 | function getContext(context) { 260 | var opts = context.options || { }; 261 | var newcontext = { arguments: { }, locals: { }, options: opts, async: options.async }; 262 | 263 | if (context.locals) 264 | for (var n in context.locals) 265 | newcontext.locals[n] = context.locals[n]; 266 | 267 | if (args) { 268 | var n = args.length; 269 | 270 | for (var k = 0; k < n; k++) 271 | newcontext.arguments[args[k].getName()] = null; 272 | } 273 | 274 | return newcontext; 275 | }; 276 | 277 | function compileArguments() { 278 | if (!args) { 279 | if (options.async) 280 | return '$cb'; 281 | return ''; 282 | } 283 | 284 | var n = args.length; 285 | var code = ''; 286 | 287 | for (var k = 0; k < n; k++) { 288 | if (code) { 289 | code += ', '; 290 | } 291 | 292 | code += args[k].getName(); 293 | } 294 | 295 | if (options.async) { 296 | if (n) 297 | code += ', '; 298 | code += '$cb'; 299 | } 300 | 301 | return code; 302 | }; 303 | }; 304 | 305 | function StopCommand() { 306 | this.compile = function(program, context) { 307 | return 'runtime.stop(0);'; 308 | } 309 | } 310 | 311 | function ExitPerformCommand() { 312 | this.compile = function(program, context) { 313 | return 'break;'; 314 | }; 315 | } 316 | 317 | function InlinePerformCommand(commands, options) 318 | { 319 | if (options.varying) { 320 | if (options.from == null) { 321 | options.from = new IntegerExpression(1); 322 | } 323 | if (options.by == null) { 324 | options.by = new IntegerExpression(1); 325 | } 326 | } 327 | 328 | this.compile = function(program, context) { 329 | var code = 'while ('; 330 | if (options.varying) { 331 | var forvariable = options.varying.compile(program, context); 332 | var step = options.by.compile(program, context); 333 | var oper = '<='; 334 | var incr = '+= ' + step; 335 | 336 | if (step === "1") { 337 | incr = '++'; 338 | } 339 | else if (step === "-1") { 340 | incr = '--'; 341 | } 342 | 343 | if (step[0] === '-') { 344 | oper = '>='; 345 | } 346 | 347 | code = 'for (' + forvariable + ' = ' + options.from.compile(program, context) + '; ' + forvariable + ' ' + oper + ' ' + options.to.compile(program, context) + '; ' + forvariable + ' ' + incr + ')'; 348 | } 349 | else { 350 | code = 'while ('; 351 | if (options.until && !options.testlast) 352 | code += '!(' + options.until.compile(program, context) + ')'; 353 | else 354 | code += 'true'; 355 | code += ')'; 356 | } 357 | 358 | code += ' { ' + commands.compile(program, context); 359 | 360 | if (options.until && options.testlast) 361 | code += ' if (!(' + options.until.compile(program, context) + ')) break;' 362 | 363 | code += ' }'; 364 | return code; 365 | } 366 | } 367 | 368 | function PerformCommand(variable, options) 369 | { 370 | options = options || { }; 371 | 372 | if (options.varying) { 373 | if (options.from == null) { 374 | options.from = new IntegerExpression(1); 375 | } 376 | if (options.by == null) { 377 | options.by = new IntegerExpression(1); 378 | } 379 | } 380 | 381 | if (options.giving && options.giving instanceof Array && options.giving.length == 1) { 382 | options.giving = options.giving[0]; 383 | } 384 | 385 | this.compile = function(program, context) { 386 | var name = variable.compile(program, context); 387 | 388 | // TODO quick hack to detect undefined 389 | if (!name || name.slice(0,10) === 'undefined.') 390 | name = variable.getName(); 391 | 392 | var code = name + '('; 393 | 394 | if (name.slice(-4) === ".new") 395 | code = "new " + name.slice(0, name.length-4) + "("; 396 | 397 | if (options.async) { 398 | var callback = getCallbackId(context); 399 | code += compileArguments(program, context, callback); 400 | code += '); function ' + callback + '(' + compileGiving(options.witherror) + ') {'; 401 | addGivingAsArguments(context, options.witherror); 402 | } 403 | else { 404 | code += compileArguments(program, context); 405 | code += ');'; 406 | } 407 | 408 | if (options.varying) { 409 | var forvariable = options.varying.compile(program, context); 410 | var step = options.by.compile(program, context); 411 | var oper = '<='; 412 | var incr = '+= ' + step; 413 | 414 | if (step === "1") { 415 | incr = '++'; 416 | } 417 | else if (step === "-1") { 418 | incr = '--'; 419 | } 420 | 421 | if (step[0] === '-') { 422 | oper = '>='; 423 | } 424 | 425 | code = 'for (' + forvariable + ' = ' + options.from.compile(program, context) + '; ' + forvariable + ' ' + oper + ' ' + options.to.compile(program, context) + '; ' + forvariable + incr + ') ' + code; 426 | } 427 | else if (!options.async && options.giving) { 428 | if (!(options.giving instanceof Array)) { 429 | code = options.giving.compile(program, context) + ' = ' + code; 430 | } else { 431 | code = 'var $aux = ' + code; 432 | var n = options.giving.length; 433 | for (var k = 0; k < n; k++) 434 | code += options.giving[k].compile(program, context) + ' = $aux;'; 435 | } 436 | } 437 | 438 | return code; 439 | }; 440 | 441 | function compileArguments(program, context, callback) 442 | { 443 | if (!options.arguments) { 444 | if (callback) 445 | return callback; 446 | return ''; 447 | } 448 | 449 | var code = ''; 450 | var n = options.arguments.length; 451 | 452 | for (var k = 0; k < n; k++) { 453 | if (code) 454 | code += ', '; 455 | 456 | code += options.arguments[k].compile(program, context); 457 | } 458 | 459 | if (callback) { 460 | if (n) 461 | code += ', '; 462 | code += callback; 463 | } 464 | 465 | return code; 466 | } 467 | 468 | function compileGiving(witherror) 469 | { 470 | if (!options.giving) { 471 | if (witherror) 472 | return 'err'; 473 | return ''; 474 | } 475 | 476 | var code = ''; 477 | 478 | if (witherror) 479 | code += 'err'; 480 | 481 | if (!(options.giving instanceof Array)) { 482 | if (code) 483 | code += ', '; 484 | code += options.giving.getName(); 485 | return code; 486 | } 487 | 488 | var n = options.giving.length; 489 | 490 | for (var k = 0; k < n; k++) { 491 | if (code) 492 | code += ', '; 493 | code += options.giving[k].getName(); 494 | } 495 | 496 | return code; 497 | } 498 | 499 | function addGivingAsArguments(context, witherror) 500 | { 501 | if (!context.arguments) 502 | context.arguments = {}; 503 | 504 | if (witherror) 505 | context.arguments['err'] = null; 506 | 507 | if (!options.giving) 508 | return; 509 | 510 | if (!(options.giving instanceof Array)) { 511 | context.arguments[options.giving.getName()] = null; 512 | return; 513 | } 514 | 515 | var n = options.giving.length; 516 | 517 | for (var k = 0; k < n; k++) { 518 | context.arguments[options.giving[k].getName()] = null; 519 | } 520 | } 521 | } 522 | 523 | function getCallbackId(context) { 524 | if (!context.ncallbacks) 525 | context.ncallbacks = 1; 526 | else 527 | context.ncallbacks++; 528 | 529 | return '$cb' + context.ncallbacks; 530 | } 531 | 532 | function CompositeCommand() 533 | { 534 | var commands = []; 535 | 536 | this.add = function(cmd) { 537 | commands.push(cmd); 538 | this.endsWithReturn = cmd.endsWithReturn; 539 | }; 540 | 541 | this.compile = function(program, context) { 542 | var initialncb = context.ncallbacks; 543 | var code = ''; 544 | var ncmd = commands.length; 545 | 546 | for (var k = 0; k < ncmd; k++) { 547 | if (k) 548 | code += ' '; 549 | code += commands[k].compile(program, context); 550 | } 551 | 552 | if (context && context.ncallbacks) { 553 | var n = context.ncallbacks; 554 | if (initialncb) 555 | n -= initialncb; 556 | for (var k = 0; k < n; k++) 557 | code += ' }'; 558 | context.ncallbacks = initialncb; 559 | } 560 | 561 | return code; 562 | }; 563 | }; 564 | 565 | function DisplayCommand(expr, noadvancing) 566 | { 567 | this.compile = function(program, context) { 568 | if (noadvancing) { 569 | return 'runtime.write(' + compileExpression(program, context) + ');'; 570 | } 571 | else { 572 | return 'runtime.display(' + compileExpression(program, context) + ');'; 573 | } 574 | } 575 | 576 | function compileExpression(program, context) { 577 | if (!(expr instanceof Array)) { 578 | return expr.compile(program, context); 579 | } 580 | 581 | var n = expr.length; 582 | var code = ''; 583 | 584 | for (var k = 0; k < n; k++) { 585 | if (code) { 586 | code += ', '; 587 | } 588 | 589 | code += expr[k].compile(program, context); 590 | } 591 | 592 | return code; 593 | }; 594 | }; 595 | 596 | function MoveCommand(expr, variable) 597 | { 598 | var variables; 599 | 600 | if (variable instanceof Array) { 601 | variables = variable; 602 | } 603 | else { 604 | variables = [ variable ]; 605 | } 606 | 607 | this.compile = function(program, context) { 608 | var code, 609 | n = variables.length; 610 | var exprcode = expr.compile(program, context); 611 | 612 | if (n == 1) 613 | if (variables[0].compileSet) 614 | return variables[0].compileSet(program, context, exprcode) + ';'; 615 | else 616 | return variables[0].compile(program, context) + ' = ' + exprcode + ';'; 617 | 618 | code = 'var $aux = ' + exprcode + ';'; 619 | 620 | for (var k = 0; k < n; k++) 621 | if (variables[k].compileSet) 622 | code = code + ' ' + variables[k].compileSet(program, context, '$aux') + ';'; 623 | else 624 | code = code + ' ' + variables[k].compile(program, context) + ' = $aux;'; 625 | 626 | return code; 627 | }; 628 | }; 629 | 630 | function BinaryToCommand(expr, variable, oper, giving, from) 631 | { 632 | if (expr instanceof Array && expr.length === 1) { 633 | expr = expr[0]; 634 | } 635 | 636 | if (variable instanceof Array && variable.length === 1) { 637 | variable = variable[0]; 638 | } 639 | 640 | if (giving instanceof Array && giving.length === 1) { 641 | giving = giving[0]; 642 | } 643 | 644 | this.compile = function(program, context) { 645 | if (!(variable instanceof Array)) { 646 | return compileTarget(program, context, variable); 647 | } 648 | 649 | var code = compileExpression(program, context) + ';'; 650 | 651 | if (from) { 652 | code = from.compile(program, context) + ' ' + oper + ' ' + code; 653 | } 654 | 655 | code = 'var $aux = ' + code; 656 | 657 | var n = variable.length; 658 | 659 | for (var k = 0; k < n; k++) { 660 | if (!giving) { 661 | if (variable[k].compileSet) 662 | code += variable[k].compileSet(program, context, variable[k].compile(program, context) + ' ' + oper + ' $aux') + ';' 663 | else 664 | code += variable[k].compile(program, context) + ' ' + oper + '= $aux;'; 665 | } 666 | else { 667 | if (variable[k].compileSet) 668 | code += variable[k].compileSet(program, context, '$aux') + ';'; 669 | else 670 | code += variable[k].compile(program, context) + ' = $aux;'; 671 | } 672 | } 673 | 674 | return code; 675 | }; 676 | 677 | function compileTarget(program, context, target) { 678 | var exprcode = compileExpression(program, context); 679 | var targetcode = target.compile(program, context); 680 | var code; 681 | 682 | if (target.compileSet) { 683 | if (oper === '=') 684 | return target.compileSet(program, context, exprcode); 685 | var suboper = oper[0]; 686 | return target.compileSet(program, context, targetcode + ' ' + suboper + ' ' + exprcode); 687 | } 688 | 689 | code = targetcode + ' = '; 690 | 691 | if (!giving) { 692 | code += targetcode + ' ' + oper + ' '; 693 | } 694 | else if (from) { 695 | code += from.compile(program, context) + ' ' + oper + ' '; 696 | } 697 | 698 | code += exprcode + ';'; 699 | 700 | return code; 701 | }; 702 | 703 | function compileExpression(program, context) { 704 | if (!(expr instanceof Array)) { 705 | return expr.compile(program, context); 706 | } 707 | 708 | var n = expr.length; 709 | var code = '('; 710 | 711 | for (var k = 0; k < n; k++) { 712 | if (code) { 713 | code += ' + '; 714 | } 715 | 716 | code += expr[k].compile(program, context); 717 | } 718 | 719 | return code + ')'; 720 | }; 721 | }; 722 | 723 | function Program() { 724 | }; 725 | 726 | Program.prototype.compileText = function() { 727 | return this.command.compile(this, {}); 728 | }; 729 | 730 | Program.prototype.compileFunction = function() { 731 | var text = this.compileText(); 732 | return compileFunction(text); 733 | }; 734 | 735 | Program.prototype.run = function(runtime) { 736 | var data = cloneData(this.data); 737 | this.procedure(runtime, this, data); 738 | return data; 739 | }; 740 | 741 | function cloneData(data) { 742 | if (!data) 743 | return null; 744 | 745 | var newdata = {}; 746 | 747 | for (var n in data) { 748 | newdata[n] = data[n]; 749 | } 750 | 751 | if (newdata.working_storage) 752 | newdata.working_storage = cloneObject(newdata.working_storage); 753 | 754 | return newdata; 755 | } 756 | 757 | function cloneObject(obj) { 758 | if (!obj) 759 | return null; 760 | 761 | if (obj instanceof Array) 762 | return obj.slice(0); 763 | 764 | var newobj = {}; 765 | 766 | for (var n in obj) { 767 | var value = obj[n]; 768 | if (typeof value === 'object') 769 | value = cloneObject(value); 770 | newobj[n] = value; 771 | } 772 | 773 | return newobj; 774 | } 775 | 776 | function compileFunction(text) { 777 | var func = new Function("runtime", "program", "data", "var ws = data ? data.working_storage : null;\r\n" + text); 778 | return func; 779 | }; 780 | 781 | function Parser(text) { 782 | var lexer = lexers.createLexer(text); 783 | var self = this; 784 | 785 | this.parseProgram = function() { 786 | var program = new Program(); 787 | 788 | program.identification = parseIdentificationDivision(); 789 | program.environment = parseEnvironmentDivision(); 790 | program.data = parseDataDivision(); 791 | program.procedures = { }; 792 | program.command = parseProcedureDivision(program.procedures); 793 | 794 | if (!program.command) 795 | program.command = this.parseProcedures(program.procedures); 796 | 797 | return program; 798 | } 799 | 800 | this.parseProcedures = function(procs) { 801 | var procedure = this.parseProcedure(procs); 802 | 803 | if (procedure == null) 804 | return null; 805 | 806 | var procedures = null; 807 | 808 | for (var proc = this.parseProcedure(procs); proc != null; proc = this.parseProcedure(procs)) { 809 | if (!procedures) { 810 | procedures = new CompositeCommand(); 811 | procedures.add(procedure); 812 | } 813 | 814 | procedures.add(proc); 815 | } 816 | 817 | if (procedures) 818 | return procedures; 819 | 820 | return procedure; 821 | }; 822 | 823 | this.parseProcedure = function(procedures) { 824 | var token = lexer.nextToken(); 825 | 826 | if (token == null) 827 | return null; 828 | 829 | if (token.type == TokenType.Name && isVerb(token.value)) { 830 | lexer.pushToken(token); 831 | return this.parseCommands(); 832 | } 833 | 834 | // If not a section, only a name/title with point, 835 | // then their commands are the continuation of the preceding ones 836 | if (tryParsePoint()) 837 | return this.parseCommands(); 838 | 839 | parseName('section'); 840 | 841 | var args = null; 842 | var options = { }; 843 | 844 | while (true) { 845 | if (!args && tryParseName("using")) { 846 | args = parseVariables(); 847 | continue; 848 | } 849 | if (!options.async && (tryParseName("async") || tryParseName("asynchronous"))) { 850 | options.async = true; 851 | continue; 852 | } 853 | break; 854 | } 855 | 856 | parsePoint(); 857 | 858 | var cmds = this.parseCommands(); 859 | 860 | procedures[normalizeName(token.value)] = null; 861 | 862 | return new ProcedureCommand(token.value, cmds, args, options); 863 | }; 864 | 865 | this.parseCommands = function(noend, followers) { 866 | var command = this.parseCommand(noend); 867 | 868 | if (command == null) 869 | return null; 870 | 871 | var commands = null; 872 | 873 | if (followers && tryPeekFollower(followers)) 874 | return command; 875 | 876 | if (noend && tryParsePoint()) 877 | return command; 878 | 879 | for (var cmd = this.parseCommand(noend); cmd != null; cmd = this.parseCommand(noend)) { 880 | if (!commands) { 881 | commands = new CompositeCommand(); 882 | commands.add(command); 883 | } 884 | 885 | commands.add(cmd); 886 | 887 | if (followers && tryPeekFollower(followers)) 888 | return commands; 889 | 890 | if (noend && tryParsePoint()) 891 | return commands; 892 | } 893 | 894 | if (commands) 895 | return commands; 896 | 897 | return command; 898 | }; 899 | 900 | this.parseCommand = function(noend) { 901 | if (tryParseName("display")) 902 | { 903 | var expr = parseTerms(); 904 | 905 | var withwith = tryParseName("with"); 906 | var noadvancing = tryParseName("no"); 907 | 908 | if (withwith || noadvancing) 909 | parseName("advancing"); 910 | else 911 | tryParseName("advancing"); 912 | 913 | if (!noend) 914 | parseEndOfCommand(); 915 | 916 | return new DisplayCommand(expr, noadvancing); 917 | } 918 | 919 | if (tryParseName("if")) 920 | { 921 | var cond = parseSimpleExpression(); 922 | parseName('then'); 923 | var thencommands = this.parseCommands(true, ['else', 'end_if']); 924 | var elsecommands = null; 925 | 926 | if (tryParseName("else")) 927 | elsecommands = this.parseCommands(true, ['end_if']); 928 | 929 | tryParseName('end_if'); 930 | 931 | if (!noend) 932 | parseEndOfCommand(); 933 | 934 | return new IfCommand(cond, thencommands, elsecommands); 935 | } 936 | 937 | if (tryParseName("return")) 938 | { 939 | var expr = parseSimpleExpression(); 940 | if (!noend) 941 | parseEndOfCommand(); 942 | 943 | return new ReturnCommand(expr); 944 | } 945 | 946 | if (tryParseName("add")) 947 | { 948 | var exprs = parseTerms(); 949 | var giving = false; 950 | 951 | if (tryParseName("giving")) 952 | giving = true; 953 | else 954 | parseName("to"); 955 | 956 | var variable = parseVariables(); 957 | var cmd = new BinaryToCommand(exprs, variable, '+', giving); 958 | 959 | if (!noend) 960 | parseEndOfCommand(); 961 | 962 | return cmd; 963 | } 964 | 965 | if (tryParseName("subtract")) 966 | { 967 | var exprs = parseTerms(); 968 | parseName("from"); 969 | var variable = parseVariables(); 970 | var cmd; 971 | 972 | if (variable.length == 1 && tryParseName("giving")) 973 | cmd = new BinaryToCommand(exprs, parseVariables(), '-', true, variable[0]); 974 | else 975 | cmd = new BinaryToCommand(exprs, variable, '-', false); 976 | 977 | if (!noend) 978 | parseEndOfCommand(); 979 | 980 | return cmd; 981 | } 982 | 983 | if (tryParseName("multiply")) 984 | { 985 | var expr = parseTerm(); 986 | parseName("by"); 987 | var variable = new VariableExpression(getName()); 988 | var cmd = new BinaryToCommand(expr, variable, '*'); 989 | 990 | if (!noend) 991 | parseEndOfCommand(); 992 | 993 | return cmd; 994 | } 995 | 996 | if (tryParseName("divide")) 997 | { 998 | var expr = parseTerm(); 999 | parseName("into"); 1000 | var variable = new VariableExpression(getName()); 1001 | var cmd = new BinaryToCommand(expr, variable, '/'); 1002 | 1003 | if (!noend) 1004 | parseEndOfCommand(); 1005 | 1006 | return cmd; 1007 | } 1008 | 1009 | if (tryParseName("move")) 1010 | { 1011 | var expr = parseTerm(); 1012 | parseName("to"); 1013 | var variables = parseVariables(); 1014 | var cmd = new MoveCommand(expr, variables); 1015 | 1016 | if (!noend) 1017 | parseEndOfCommand(); 1018 | 1019 | return cmd; 1020 | } 1021 | 1022 | if (tryParseName("stop")) 1023 | { 1024 | tryParseName("run"); 1025 | var cmd = new StopCommand(); 1026 | 1027 | if (!noend) 1028 | parseEndOfCommand(); 1029 | 1030 | return cmd; 1031 | } 1032 | 1033 | if (tryParseName("local") || tryParseName("locals")) 1034 | { 1035 | var names = parseNames(); 1036 | var cmd = new LocalCommand(names); 1037 | 1038 | if (!noend) 1039 | parseEndOfCommand(); 1040 | 1041 | return cmd; 1042 | } 1043 | 1044 | if (tryParseName("global") || tryParseName("globals")) { 1045 | var names = parseNames(); 1046 | var cmd = new GlobalCommand(names); 1047 | 1048 | if (!noend) 1049 | parseEndOfCommand(); 1050 | 1051 | return cmd; 1052 | } 1053 | 1054 | if (tryParseName("exit")) { 1055 | parseName('perform'); 1056 | var cmd = new ExitPerformCommand(); 1057 | 1058 | if (!noend) 1059 | parseEndOfCommand(); 1060 | 1061 | return cmd; 1062 | } 1063 | 1064 | if (tryParseName("perform")) 1065 | { 1066 | var options = { }; 1067 | 1068 | if (tryPeekReservedName()) { 1069 | var token = lexer.nextToken(); 1070 | 1071 | // TODO to allow 'perform write in perform', using reserved word in qualified invocation 1072 | if (tryPeekName("in")) 1073 | lexer.pushToken(token); 1074 | else { 1075 | lexer.pushToken(token); 1076 | 1077 | while (true) { 1078 | if (!options.until && tryParseName("until")) 1079 | options.until = parseSimpleExpression(); 1080 | else if (options.until && !options.testlast && !options.testfirst && tryParseName("with")) { 1081 | parseName("test"); 1082 | if (tryParseName("last")) 1083 | options.testlast = true; 1084 | else { 1085 | parseName("first"); 1086 | options.testfirst = true; 1087 | } 1088 | } 1089 | else if (options.until && tryParseName("test")) { 1090 | if (tryParseName("last")) 1091 | options.testlast = true; 1092 | else { 1093 | parseName("first"); 1094 | options.testfirst = true; 1095 | } 1096 | } 1097 | else if (!options.until && !options.varying && tryParseName("varying")) { 1098 | options.varying = parseVariable(); 1099 | if (tryParseName("from")) 1100 | options.from = parseTerm(); 1101 | if (tryParseName("to")) 1102 | options.to = parseTerm(); 1103 | if (tryParseName("by")) 1104 | options.by = parseTerm(); 1105 | } 1106 | else 1107 | break; 1108 | } 1109 | 1110 | var cmds = this.parseCommands(true, ['end_perform']); 1111 | 1112 | tryParseName('end_perform'); 1113 | 1114 | if (!noend) 1115 | parseEndOfCommand(); 1116 | 1117 | return new InlinePerformCommand(cmds, options); 1118 | } 1119 | } 1120 | 1121 | var variable = parseVariable(); 1122 | 1123 | while (true) { 1124 | if (!options.giving && !options.varying && !options.async && tryParseName("varying")) { 1125 | options.varying = parseVariable(); 1126 | if (tryParseName("from")) 1127 | options.from = parseTerm(); 1128 | if (tryParseName("to")) 1129 | options.to = parseTerm(); 1130 | if (tryParseName("by")) 1131 | options.by = parseTerm(); 1132 | continue; 1133 | } 1134 | 1135 | if (!options.arguments && tryParseName("using")) { 1136 | options.arguments = parseTerms(); 1137 | continue; 1138 | } 1139 | 1140 | if (!options.varying && !options.giving && tryParseName("giving")) { 1141 | options.giving = parseVariables(); 1142 | continue; 1143 | } 1144 | 1145 | if (!options.varying && (tryParseName("async") || tryParseName("asynchronous"))) { 1146 | options.async = true; 1147 | tryParseName("with"); 1148 | options.witherror = tryParseName("error"); 1149 | continue; 1150 | } 1151 | 1152 | break; 1153 | } 1154 | 1155 | var cmd = new PerformCommand(variable, options); 1156 | 1157 | if (!noend) 1158 | parseEndOfCommand(); 1159 | 1160 | return cmd; 1161 | } 1162 | }; 1163 | 1164 | function parseIdentificationDivision() { 1165 | return parseParagraph("identification", "division", ["environment", "data", "procedure"]); 1166 | }; 1167 | 1168 | function parseEnvironmentDivision() { 1169 | return parseParagraph("environment", "division", ["data", "procedure"], "section"); 1170 | }; 1171 | 1172 | function parseDataDivision() { 1173 | return parseParagraph("data", "division", ["procedure"], "section"); 1174 | }; 1175 | 1176 | function parseProcedureDivision(procedures) { 1177 | var token = lexer.nextToken(); 1178 | 1179 | if (!token) 1180 | return null; 1181 | 1182 | if (token.type != TokenType.Name || token.value.toLowerCase() != "procedure") { 1183 | lexer.pushToken(token); 1184 | return null; 1185 | } 1186 | 1187 | parseName("division"); 1188 | parsePoint(); 1189 | 1190 | var command = self.parseProcedures(procedures); 1191 | 1192 | if (!command) 1193 | return null; 1194 | 1195 | return command; 1196 | }; 1197 | 1198 | function parseParagraph(name, kind, followers, child) { 1199 | var object = { }; 1200 | if (!tryParseName(name)) 1201 | return null; 1202 | parseName(kind); 1203 | parsePoint(); 1204 | 1205 | if (child) 1206 | parseChildren(object, child, followers); 1207 | else 1208 | parseAttributes(object, followers); 1209 | 1210 | return object; 1211 | } 1212 | 1213 | function parseChildren(object, kind, followers) { 1214 | for (var token = lexer.nextToken(); token != null && token.type == TokenType.Name && followers.indexOf(token.value.toLowerCase()) == -1; token = lexer.nextToken()) 1215 | { 1216 | var name = normalizeName(token.value); 1217 | parseName(kind); 1218 | parsePoint(); 1219 | 1220 | object[name] = { }; 1221 | 1222 | if (name == "working_storage" && kind == "section") 1223 | parseWorkingStorage(object[name]); 1224 | else if (name == "linkage" && kind == "section") 1225 | parseLinkage(object[name]); 1226 | else 1227 | parseAttributes(object[name], followers); 1228 | } 1229 | 1230 | if (token) 1231 | lexer.pushToken(token); 1232 | } 1233 | 1234 | function parseAttributes(object, followers) { 1235 | for (var token = lexer.nextToken(); token != null && token.type == TokenType.Name && followers.indexOf(token.value.toLowerCase()) == -1; token = lexer.nextToken()) 1236 | { 1237 | var name = normalizeName(token.value); 1238 | parsePoint(); 1239 | 1240 | var value = lexer.nextPhrase(); 1241 | object[name] = value; 1242 | } 1243 | 1244 | if (token) 1245 | lexer.pushToken(token); 1246 | }; 1247 | 1248 | function parseWorkingStorage(object) 1249 | { 1250 | parseItems(object, "01"); 1251 | } 1252 | 1253 | function parseLinkage(object) 1254 | { 1255 | parseItems(object, "01"); 1256 | } 1257 | 1258 | function parseItems(object, level) 1259 | { 1260 | while (tryParse(level, TokenType.Integer)) 1261 | parseItem(object, level); 1262 | } 1263 | 1264 | function parseItem(object, level) 1265 | { 1266 | var name = normalizeName(getName()); 1267 | parsePoint(); 1268 | object[name] = null; 1269 | 1270 | for (var newlevel = tryGetInteger(); newlevel && newlevel > level; newlevel = tryGetInteger()) 1271 | { 1272 | if (object[name] == null) 1273 | object[name] = { }; 1274 | 1275 | lexer.pushToken(lexers.createToken(newlevel, TokenType.Integer)); 1276 | 1277 | parseItems(object[name], newlevel); 1278 | } 1279 | 1280 | if (newlevel != null) 1281 | lexer.pushToken(lexers.createToken(newlevel, TokenType.Integer)); 1282 | }; 1283 | 1284 | function parseVariables() { 1285 | var list = []; 1286 | list.push(parseVariable()); 1287 | 1288 | while (true) { 1289 | while (tryParse(",", TokenType.Punctuation)) 1290 | list.push(parseVariable()); 1291 | 1292 | var token = lexer.nextToken(); 1293 | if (token == null) 1294 | break; 1295 | lexer.pushToken(token); 1296 | 1297 | if (token.type != TokenType.Name || (token.type == TokenType.Name && isReserved(token.value))) 1298 | break; 1299 | 1300 | list.push(parseVariable()); 1301 | } 1302 | 1303 | return list; 1304 | }; 1305 | 1306 | function parseVariable() { 1307 | var name = getName(); 1308 | 1309 | if (tryParse('(', TokenType.Punctuation)) { 1310 | var index = parseSimpleExpression(); 1311 | parseToken(')', TokenType.Punctuation); 1312 | return new IndexedVariableExpression(name, index); 1313 | } 1314 | 1315 | if (!tryParseName("in")) 1316 | return new VariableExpression(name); 1317 | 1318 | var names = [ name ]; 1319 | 1320 | for (names.unshift(getName()); tryParseName("in");) 1321 | names.unshift(getName()); 1322 | 1323 | return new QualifiedVariableExpression(names); 1324 | }; 1325 | 1326 | function parseNames() { 1327 | var names = [ getName() ]; 1328 | 1329 | var name; 1330 | 1331 | for (tryParse(',', TokenType.Punctuation); (name = tryGetName()) != null; tryParse(',', TokenType.Punctuation)) 1332 | names.push(name); 1333 | 1334 | return names; 1335 | }; 1336 | 1337 | function parseSimpleExpression() { 1338 | var left = parseTerm(); 1339 | 1340 | if (left == null) 1341 | return null; 1342 | 1343 | var oper = tryGetOperator(); 1344 | 1345 | if (!oper) 1346 | return left; 1347 | 1348 | var right = parseTerm(); 1349 | 1350 | return new BinaryExpression(left, oper, right); 1351 | }; 1352 | 1353 | function parseTerms() { 1354 | var list = []; 1355 | list.push(parseTerm()); 1356 | 1357 | while (true) { 1358 | while (tryParse(",", TokenType.Punctuation)) 1359 | list.push(parseTerm()); 1360 | 1361 | var token = lexer.nextToken(); 1362 | if (token == null) 1363 | break; 1364 | lexer.pushToken(token); 1365 | 1366 | if (token.type == TokenType.Punctuation || (token.type == TokenType.Name && isReserved(token.value))) 1367 | break; 1368 | 1369 | list.push(parseTerm()); 1370 | } 1371 | 1372 | return list; 1373 | }; 1374 | 1375 | function parseTerm() { 1376 | var token = lexer.nextToken(); 1377 | 1378 | if (!token) 1379 | return null; 1380 | 1381 | if (token.type === TokenType.String) 1382 | return new StringExpression(token.value); 1383 | 1384 | if (token.type === TokenType.Integer) 1385 | return new IntegerExpression(token.value); 1386 | 1387 | if (token.type === TokenType.Name) { 1388 | lexer.pushToken(token); 1389 | return parseVariable(); 1390 | } 1391 | }; 1392 | 1393 | function parseEndOfCommand() { 1394 | var token = lexer.nextToken(); 1395 | 1396 | if (!token) 1397 | return; 1398 | 1399 | if (token.value === "." && token.type === TokenType.Punctuation) 1400 | return; 1401 | 1402 | if (token.type === TokenType.Name && isVerb(token.value)) { 1403 | lexer.pushToken(token); 1404 | return; 1405 | } 1406 | 1407 | throw "unexpected '" + token.value + "'"; 1408 | }; 1409 | 1410 | function parseToken(value, type) 1411 | { 1412 | if (!tryParse(value, type)) 1413 | throw "expected '" + value + "'"; 1414 | } 1415 | 1416 | function parsePoint() 1417 | { 1418 | if (!tryParse('.', TokenType.Punctuation)) 1419 | throw "expected '.'"; 1420 | } 1421 | 1422 | function tryPeekFollower(followers) 1423 | { 1424 | if (!followers || !followers.length) 1425 | return false; 1426 | 1427 | var token = lexer.peekToken(); 1428 | 1429 | if (token == null) 1430 | return false; 1431 | 1432 | if (token.type != TokenType.Name) 1433 | return false; 1434 | 1435 | var name = normalizeName(token.value); 1436 | 1437 | return followers.indexOf(name) >= 0; 1438 | } 1439 | 1440 | function tryPeekReservedName() 1441 | { 1442 | var token = lexer.peekToken(); 1443 | 1444 | if (token != null && token.type === TokenType.Name && isReserved(token.value)) 1445 | return true; 1446 | 1447 | return false; 1448 | } 1449 | 1450 | function tryPeekName(name) 1451 | { 1452 | var token = lexer.peekToken(); 1453 | 1454 | if (token != null && token.type === TokenType.Name && normalizeName(token.value) === name) 1455 | return true; 1456 | 1457 | return false; 1458 | } 1459 | 1460 | function tryParsePoint() 1461 | { 1462 | return tryParse('.', TokenType.Punctuation); 1463 | } 1464 | 1465 | function parseName(name) { 1466 | if (!tryParseName(name)) 1467 | throw "expected '" + name + "'"; 1468 | } 1469 | 1470 | function tryParseName(name) { 1471 | return tryParse(name, TokenType.Name); 1472 | 1473 | return true; 1474 | }; 1475 | 1476 | function tryGetInteger() { 1477 | var token = lexer.nextToken(); 1478 | 1479 | if (token == null) 1480 | return null; 1481 | 1482 | if (token.type != TokenType.Integer) 1483 | { 1484 | lexer.pushToken(token); 1485 | return null; 1486 | } 1487 | 1488 | return token.value; 1489 | }; 1490 | 1491 | function tryGetOperator() { 1492 | var token = lexer.nextToken(); 1493 | 1494 | if (token == null) 1495 | return null; 1496 | 1497 | if (token.type != TokenType.Operator) 1498 | { 1499 | lexer.pushToken(token); 1500 | return null; 1501 | } 1502 | 1503 | return token.value; 1504 | }; 1505 | 1506 | function tryGetName() { 1507 | var token = lexer.nextToken(); 1508 | 1509 | if (token == null) 1510 | return null; 1511 | 1512 | if (token.type != TokenType.Name || isReserved(token.value)) 1513 | { 1514 | lexer.pushToken(token); 1515 | return null; 1516 | } 1517 | 1518 | return token.value; 1519 | }; 1520 | 1521 | function tryParse(value, type) { 1522 | var token = lexer.nextToken(); 1523 | 1524 | if (token == null || token.type != type || normalizeName(token.value) != value) 1525 | { 1526 | lexer.pushToken(token); 1527 | return false; 1528 | } 1529 | 1530 | return true; 1531 | }; 1532 | 1533 | function getName() { 1534 | var token = lexer.nextToken(); 1535 | 1536 | if (token == null) 1537 | throw "unexpected end of input"; 1538 | 1539 | if (token.type != TokenType.Name) 1540 | { 1541 | lexer.pushToken(token); 1542 | throw "unexpected '" + token.value + "'"; 1543 | } 1544 | 1545 | return token.value; 1546 | }; 1547 | 1548 | }; 1549 | 1550 | function normalizeName(name) { 1551 | if (name.indexOf('_') >= 0) 1552 | return name; 1553 | 1554 | var n = name.length; 1555 | var nlower = 0; 1556 | var nupper = 0; 1557 | 1558 | for (var k = 0; k < n; k++) 1559 | if (isUpperCase(name[k])) 1560 | nupper++; 1561 | else if (isLowerCase(name[k])) 1562 | nlower++; 1563 | 1564 | if (nupper && nlower) 1565 | return name; 1566 | 1567 | var name = name.toLowerCase(); 1568 | name = name.replace(/-/g, '_'); 1569 | return name; 1570 | }; 1571 | 1572 | function isUpperCase(ch) 1573 | { 1574 | return ch >= 'A' && ch <= 'Z'; 1575 | }; 1576 | 1577 | function isLowerCase(ch) 1578 | { 1579 | return ch >= 'a' && ch <= 'z'; 1580 | }; 1581 | 1582 | function isReserved(name) { 1583 | name = normalizeName(name); 1584 | return reserved.indexOf(name) >= 0 || verbs.indexOf(name) >= 0; 1585 | }; 1586 | 1587 | function isVerb(name) { 1588 | name = normalizeName(name); 1589 | return verbs.indexOf(name) >= 0; 1590 | }; 1591 | 1592 | function createParser(text) { 1593 | return new Parser(text); 1594 | }; 1595 | 1596 | module.exports = { 1597 | createParser: createParser 1598 | } 1599 | 1600 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { "name": "cobolscript" 2 | , "description": "COBOL compiler to JavaScript" 3 | , "keywords": [ "cobol", "interpreter", "compiler", "javascript" ] 4 | , "version": "0.0.1" 5 | , "author": "Angel 'Java' Lopez (http://www.ajlopez.com)" 6 | , "repository": { "type": "git", "url": "git://github.com/ajlopez/CobolScript.git" } 7 | , "main": "./lib/cobolscript.js" 8 | , "engines": { "node": ">= 8.0.0" } 9 | , "scripts": { 10 | "test": "simpleunit test" 11 | } 12 | , "dependencies": { 13 | } 14 | , "devDependencies": { 15 | "simpleunit": "0.0.9" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /samples/factorial/README.md: -------------------------------------------------------------------------------- 1 | # Factorial Sample 2 | 3 | This sample shows the use of user defined functions. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | ## Run 10 | 11 | With the command line: 12 | ``` 13 | node run factorial.cob 14 | ``` 15 | 16 | The output: 17 | ``` 18 | 1! = 1 19 | 2! = 2 20 | 3! = 6 21 | 4! = 24 22 | 5! = 120 23 | 6! = 720 24 | 7! = 5040 25 | 8! = 40320 26 | 9! = 362880 27 | 10! = 3628800 28 | ``` 29 | 30 | factorial.cob declares a variable in working storage section (without using picture, yet): 31 | ```cobol 32 | data division. 33 | working-storage section. 34 | 01 n. 35 | ``` 36 | 37 | The procedure division has a loop: 38 | ```cobol 39 | procedure division. 40 | perform show-factorial varying n from 1 to 10. 41 | ``` 42 | 43 | show-factorial procedure calls factorial using `using` to pass an argument, and `giving` to 44 | save the result. Then, it shows the result using `display`. Note the declaration and use of 45 | a local variable `result`. 46 | ```cobol 47 | show-factorial. 48 | local result. 49 | perform factorial using n giving result. 50 | display n "! = " result. 51 | ``` 52 | 53 | factorial procedure invokes itself recursively 54 | ```cobol 55 | factorial using n. 56 | local m. 57 | if n = 1 then return n. 58 | subtract 1 from n giving m. 59 | perform factorial using m giving m. 60 | multiply n by m. 61 | return m. 62 | ``` -------------------------------------------------------------------------------- /samples/factorial/factorial.cob: -------------------------------------------------------------------------------- 1 | data division. 2 | working-storage section. 3 | 01 n. 4 | 5 | procedure division. 6 | perform show-factorial varying n from 1 to 10. 7 | 8 | show-factorial section. 9 | local result. 10 | perform factorial using n giving result. 11 | display n "! = " result. 12 | 13 | factorial section using n. 14 | local m. 15 | if n = 1 then return n. 16 | subtract 1 from n giving m. 17 | perform factorial using m giving m. 18 | multiply n by m. 19 | return m. 20 | 21 | 22 | -------------------------------------------------------------------------------- /samples/factorial/run.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), fs = require('fs'); function runFile(filename) { cobs.compileProgramFile(filename).run(cobs.getRuntime()); }; process.argv.forEach(function(val) { if (val.slice(-4) == ".cob") runFile(val); }); -------------------------------------------------------------------------------- /samples/factorialweb/README.md: -------------------------------------------------------------------------------- 1 | # Factorial Web Sample 2 | 3 | The output of a program can be used to make a web page. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | ## Run 10 | 11 | With the command line: 12 | ``` 13 | node server 14 | ``` 15 | 16 | The output: 17 | ``` 18 | Server started, listening at port 8000 19 | ``` 20 | 21 | Then launch http://localhost:8000 in your browser. It works! 22 | 23 | ![Factorial Web Sample](https://raw.github.com/ajlopez/CobolScript/master/images/factorialweb.jpg) 24 | 25 | -------------------------------------------------------------------------------- /samples/factorialweb/factorial.cob: -------------------------------------------------------------------------------- 1 | data division. 2 | working-storage section. 3 | 01 n. 4 | 5 | procedure division. 6 | display "

Factorial

". 7 | display "

Page generated by CobolScript

". 8 | display "". 9 | display "". 10 | perform show-factorial varying n from 1 to 10. 11 | display "
nn!
". 12 | stop run. 13 | 14 | show-factorial section. 15 | local result. 16 | perform factorial using n giving result. 17 | display "" n "" result "". 18 | 19 | factorial section using n. 20 | local m. 21 | if n = 1 then return n. 22 | subtract 1 from n giving m. 23 | perform factorial using m giving m. 24 | multiply n by m. 25 | return m. 26 | 27 | 28 | -------------------------------------------------------------------------------- /samples/factorialweb/server.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), http = require('http'), fs = require('fs'); var program = cobs.compileProgramFile('./factorial.cob'); http.createServer(function(req, res) { program.run(cobs.getRuntime({ request: req, response: res })); }).listen(8000); console.log('Server started, listening at port 8000'); -------------------------------------------------------------------------------- /samples/hello/README.md: -------------------------------------------------------------------------------- 1 | # Hello Sample 2 | 3 | The clasical program, using `display` verb. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | ## Run 10 | 11 | With the command line: 12 | ``` 13 | node run hello.cob 14 | ``` 15 | 16 | The output: 17 | ``` 18 | Hello, world 19 | ``` 20 | 21 | hello.cob is simple 22 | ```cobol 23 | display "Hello, world". 24 | ``` 25 | 26 | With the command line: 27 | ``` 28 | node compile hello.cob 29 | ``` 30 | 31 | The output is: 32 | ``` 33 | runtime.display("Hello, world"); 34 | ``` 35 | 36 | The runtime is an object provided by CobolScript implementation. 37 | 38 | CobolScript doesn't enforce to have all the common COBOL declarations: identification division, environment 39 | division, data division and procedure division. You can write directly the commands. 40 | 41 | It supports a more complete program `hello2.cob`: 42 | ```cobol 43 | IDENTIFICATION DIVISION. 44 | PROGRAM-ID. HELLO. 45 | ENVIRONMENT DIVISION. 46 | DATA DIVISION. 47 | PROCEDURE DIVISION. 48 | 49 | PROGRAM-BEGIN. 50 | DISPLAY "Hello world". 51 | 52 | PROGRAM-DONE. 53 | STOP RUN. 54 | ``` 55 | -------------------------------------------------------------------------------- /samples/hello/compile.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), fs = require('fs'); function compileFile(filename) { return cobs.compileProgramFile(filename).compileText(); }; process.argv.forEach(function(val) { if (val.slice(-4) == ".cob") console.log(compileFile(val)); }); -------------------------------------------------------------------------------- /samples/hello/hello.cob: -------------------------------------------------------------------------------- 1 | display "Hello, world". -------------------------------------------------------------------------------- /samples/hello/hello2.cob: -------------------------------------------------------------------------------- 1 | IDENTIFICATION DIVISION. 2 | PROGRAM-ID. HELLO. 3 | ENVIRONMENT DIVISION. 4 | DATA DIVISION. 5 | PROCEDURE DIVISION. 6 | 7 | PROGRAM-BEGIN. 8 | DISPLAY "Hello world". 9 | 10 | PROGRAM-DONE. 11 | STOP RUN. -------------------------------------------------------------------------------- /samples/hello/run.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), fs = require('fs'); function runFile(filename) { cobs.compileProgramFile(filename).run(cobs.getRuntime()); }; process.argv.forEach(function(val) { if (val.slice(-4) == ".cob") runFile(val); }); -------------------------------------------------------------------------------- /samples/helloasync/README.md: -------------------------------------------------------------------------------- 1 | # Hello Asynchronous Sample 2 | 3 | The clasical program, using `perform ... async [with error]` and `display` verbs. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | ## Run 10 | 11 | With the command line: 12 | ``` 13 | node run hello.cob 14 | ``` 15 | 16 | The output: 17 | ``` 18 | Hello, World 19 | ``` 20 | 21 | hello.cob code: 22 | ```cobol 23 | procedure division. 24 | perform sayhello async. 25 | local name. 26 | perform getname async giving name. 27 | display name. 28 | 29 | sayhello async. 30 | display "Hello, " with no advancing. 31 | 32 | getname asynchronous. 33 | return "World". 34 | ``` 35 | 36 | Usually a perform code like this: 37 | ``` 38 | procedure division. 39 | perform sayhello. 40 | display "World". 41 | 42 | sayhello. 43 | display "Hello, " with no advancing. 44 | ``` 45 | 46 | is compiled to: 47 | ```javascript 48 | sayhello(); 49 | runtime.display("World"); 50 | function sayhello() { 51 | runtime.write("Hello "); 52 | } 53 | ``` 54 | 55 | Instead a perform async code: 56 | ``` 57 | procedure division. 58 | perform sayhello async. 59 | display "World". 60 | 61 | sayhello async. 62 | display "Hello, " with no advancing. 63 | ``` 64 | 65 | is compiled using callbacks to: 66 | ```javascript 67 | sayhello($cb1); 68 | function $cb1() { 69 | runtime.display("World "); 70 | } 71 | function sayhello($cb) { 72 | runtime.write("Hello "); 73 | $cb(); 74 | } 75 | ``` 76 | 77 | You MUST use async in both places: at perform invocation and procedure declaration. 78 | 79 | -------------------------------------------------------------------------------- /samples/helloasync/hello.cob: -------------------------------------------------------------------------------- 1 | procedure division. 2 | perform sayhello async. 3 | local name. 4 | perform getname async giving name. 5 | display name. 6 | 7 | sayhello section async. 8 | display "Hello, " with no advancing. 9 | 10 | getname section asynchronous. 11 | return "World". 12 | -------------------------------------------------------------------------------- /samples/helloasync/run.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), fs = require('fs'); function runFile(filename) { cobs.compileProgramFile(filename).run(cobs.getRuntime()); }; process.argv.forEach(function(val) { if (val.slice(-4) == ".cob") runFile(val); }); -------------------------------------------------------------------------------- /samples/hellopgm/README.md: -------------------------------------------------------------------------------- 1 | # Hello Program Sample 2 | 3 | The clasical program, using a complete declaration of divisions. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | ## Run 10 | 11 | With the command line: 12 | ``` 13 | node run hello.cob 14 | ``` 15 | 16 | The output: 17 | ``` 18 | Hello, world 19 | ``` 20 | 21 | hello.cob has the clasical four COBOL divisions declared: 22 | ```cobol 23 | identification division. 24 | program-id. hello. 25 | author. A.J.Lopez. 26 | installation. test. 27 | date-written. 2012-12-22. 28 | date-compiled. 2012-12-22. 29 | environment division. 30 | configuration section. 31 | source-computer. node. 32 | object-computer. node. 33 | data division. 34 | procedure division. 35 | display "Hello, world". 36 | ``` 37 | -------------------------------------------------------------------------------- /samples/hellopgm/hello.cob: -------------------------------------------------------------------------------- 1 | identification division. program-id. hello. author. A.J.Lopez. installation. test. date-written. 2012-12-22. date-compiled. 2012-12-22. environment division. configuration section. source-computer. node. object-computer. node. data division. procedure division. display "Hello, world". -------------------------------------------------------------------------------- /samples/hellopgm/run.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), fs = require('fs'); function runFile(filename) { cobs.compileProgramFile(filename).run(cobs.getRuntime()); }; process.argv.forEach(function(val) { if (val.slice(-5) == ".cobs" || val.slice(-4) == ".cob") runFile(val); }); -------------------------------------------------------------------------------- /samples/helloweb/README.md: -------------------------------------------------------------------------------- 1 | # Hello Web Sample 2 | 3 | The output of a program makes a web page. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | ## Run 10 | 11 | With the command line: 12 | ``` 13 | node server 14 | ``` 15 | 16 | The output: 17 | ``` 18 | Server started, listening at port 8000 19 | ``` 20 | 21 | Then launch http://localhost:8000 in your browser. It works! 22 | 23 | ![Factorial Web Sample](https://raw.github.com/ajlopez/CobolScript/master/images/helloweb.jpg) 24 | 25 | -------------------------------------------------------------------------------- /samples/helloweb/hello.cob: -------------------------------------------------------------------------------- 1 | display "

Hello, world

". display "

Generated by CobolScript

". stop run. -------------------------------------------------------------------------------- /samples/helloweb/server.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), http = require('http'), fs = require('fs'); var program = cobs.compileProgramFile('./hello.cob'); http.createServer(function(req, res) { program.run(cobs.getRuntime({ request: req, response: res })); }).listen(8000); console.log('Server started, listening at port 8000'); -------------------------------------------------------------------------------- /samples/linkage/README.md: -------------------------------------------------------------------------------- 1 | # Hello Web Sample 2 | 3 | The output of a program makes a web page. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | ## Run 10 | 11 | With the command line: 12 | ``` 13 | node server 14 | ``` 15 | 16 | The output: 17 | ``` 18 | Server started, listening at port 8000 19 | ``` 20 | 21 | Then launch http://localhost:8000 in your browser. It works! 22 | 23 | ![Factorial Web Sample](https://raw.github.com/ajlopez/CobolScript/master/images/helloweb.jpg) 24 | 25 | -------------------------------------------------------------------------------- /samples/linkage/hello.cob: -------------------------------------------------------------------------------- 1 | data division. linkage section. 01 request. 01 response. procedure division. local content. move object to content. move "text/plain" to content("Content-Type"). perform writeHead in response using 200, content. display "Hello, world". -------------------------------------------------------------------------------- /samples/linkage/server.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), http = require('http'), fs = require('fs'); var program = cobs.compileProgramFile('./hello.cob'); http.createServer(function(req, res) { program.run(cobs.getRuntime({ request: req, response: res })); }).listen(8000); console.log('Server started, listening at port 8000'); -------------------------------------------------------------------------------- /samples/local/README.md: -------------------------------------------------------------------------------- 1 | # Local Sample 2 | 3 | This sample shows the declaration and use of local variable. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | ## Run 10 | 11 | With the command line: 12 | ``` 13 | node run factorial.cob 14 | ``` 15 | 16 | The output: 17 | ``` 18 | 1! = 1 19 | 2! = 2 20 | 3! = 6 21 | 4! = 24 22 | 5! = 120 23 | 6! = 720 24 | 7! = 5040 25 | 8! = 40320 26 | 9! = 362880 27 | 10! = 3628800 28 | ``` 29 | 30 | factorial.cob declares a variable directly in the implicit procedure division: 31 | ```cobol 32 | local n. 33 | ``` 34 | 35 | The show-factorial procedure is invoked in a loop, varying the local variable: 36 | ```cobol 37 | procedure division. 38 | perform show-factorial varying n from 1 to 10. 39 | ``` 40 | 41 | show-factorial procedure calls factorial using `using` to pass an argument, and `giving` to 42 | save the result. Then, it shows the result using `display`. Note the declaration and use of 43 | a local variable `result`. 44 | ```cobol 45 | show-factorial. 46 | local result. 47 | perform factorial using n giving result. 48 | display n "! = " result. 49 | ``` 50 | 51 | factorial procedure invokes itself recursively. It uses a local variable `m`. 52 | ```cobol 53 | factorial using n. 54 | local m. 55 | if n = 1 then return n. 56 | subtract 1 from n giving m. 57 | perform factorial using m giving m. 58 | multiply n by m. 59 | return m. 60 | ``` -------------------------------------------------------------------------------- /samples/local/factorial.cob: -------------------------------------------------------------------------------- 1 | 2 | * using a local variable instead of an item 01 in working-storage section 3 | 4 | local n. 5 | perform show-factorial using n varying n from 1 to 10. 6 | 7 | show-factorial section using n. 8 | local result. 9 | perform factorial using n giving result. 10 | display n "! = " result. 11 | 12 | factorial section using n. 13 | local m. 14 | if n = 1 then return n. 15 | subtract 1 from n giving m. 16 | perform factorial using m giving m. 17 | multiply n by m. 18 | return m. 19 | 20 | 21 | -------------------------------------------------------------------------------- /samples/local/run.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), fs = require('fs'); function runFile(filename) { cobs.compileProgramFile(filename).run(cobs.getRuntime()); }; process.argv.forEach(function(val) { if (val.slice(-4) == ".cob") runFile(val); }); -------------------------------------------------------------------------------- /samples/mysql/README.md: -------------------------------------------------------------------------------- 1 | # MySQL Sample 2 | 3 | CobolScript can access MySQL server using a Node.js module. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | Then, execute at command line: 10 | ``` 11 | npm install 12 | ``` 13 | 14 | This command installs the `mysql` module, according to the dependecies described in `package.json` file. 15 | 16 | ## Run 17 | 18 | With the command line: 19 | ``` 20 | node run showdb.cob 21 | ``` 22 | 23 | The program connects to the MySQL server at localhost and list its database. The server must be running. 24 | 25 | The code 26 | ``` 27 | perform require using "mysql" giving mysql. 28 | ``` 29 | loads the `mysql` module. 30 | 31 | Then 32 | ``` 33 | local options. 34 | 35 | move object to options. 36 | move "root" to user in options. 37 | move "" to password in options. 38 | 39 | local connection. 40 | 41 | perform createConnection in mysql using options giving connection. 42 | ``` 43 | opens the connection. 44 | 45 | The code 46 | ``` 47 | perform query in connection using "show databases" showdbs. 48 | 49 | showdbs section using err, rows, fields. 50 | * .... 51 | ``` 52 | pass `showdbs` as a callback to asynchronous method `query` in `connection`. The callbacks accept three parameters. 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /samples/mysql/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mysql-examples", 3 | "version": "0.0.1", 4 | "private": true, 5 | "dependencies": { 6 | "mysql": "*" 7 | } 8 | } -------------------------------------------------------------------------------- /samples/mysql/run.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), fs = require('fs'); function runFile(filename) { cobs.compileProgramFile(filename).run(cobs.getRuntime({ require: require })); }; process.argv.forEach(function(val) { if (val.slice(-4) == ".cob") runFile(val); }); -------------------------------------------------------------------------------- /samples/mysql/showdb.cob: -------------------------------------------------------------------------------- 1 | data division. linkage section. 01 global. 01 require. procedure division. local mysql. perform require using "mysql" giving mysql. local options. move object to options. move "root" to user in options. move "" to password in options. local connection. perform createConnection in mysql using options giving connection. perform query in connection using "show databases" showdbs. showdbs section using err, rows, fields. if err then display err stop run end-if. local k. local n. move length in rows to n. local row. perform varying k from 1 to n move rows(k) to row display Database in row end-perform. stop run. -------------------------------------------------------------------------------- /samples/mysqlweb/README.md: -------------------------------------------------------------------------------- 1 | # MySQL Web Sample 2 | 3 | CobolScript can access MySQL server using a Node.js module, 4 | and listing databases, tables and columns in dynamic web pages. 5 | 6 | ## Setup 7 | 8 | Install [Node.js](http://nodejs.org). 9 | 10 | Then, execute at command line: 11 | ``` 12 | npm install 13 | ``` 14 | 15 | This command installs the `mysql` module, according to the dependecies described in `package.json` file. 16 | 17 | ## Run 18 | 19 | With the command line: 20 | ``` 21 | node server 22 | ``` 23 | 24 | The output: 25 | ``` 26 | Server started, listening at port 8000 27 | ``` 28 | 29 | The program connects to the MySQL server at localhost and list its database. The server must be running. 30 | 31 | In the pages, the code 32 | ``` 33 | perform require using "mysql" giving mysql. 34 | ``` 35 | loads the `mysql` module. 36 | 37 | Then 38 | ``` 39 | local options. 40 | 41 | move object to options. 42 | move "root" to user in options. 43 | move "" to password in options. 44 | 45 | local connection. 46 | 47 | perform createConnection in mysql using options giving connection. 48 | ``` 49 | opens the connection. 50 | 51 | The code 52 | ``` 53 | perform query in connection using "show databases" showdbs. 54 | 55 | showdbs section using err, rows, fields. 56 | * .... 57 | ``` 58 | pass `showdbs` as a callback to asynchronous method `query` in `connection`. The callbacks accept three parameters. 59 | 60 | -------------------------------------------------------------------------------- /samples/mysqlweb/database.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 request. 5 | 02 response. 6 | 03 require. 7 | 8 | procedure division. 9 | local mysql. 10 | local databasename. 11 | 12 | move name in params in request to databasename. 13 | #> 14 |

Database ${databasename}

15 |
16 | Databases 17 |
18 |

Tables

19 | <# 20 | 21 | perform require using "mysql" giving mysql. 22 | 23 | local options. 24 | 25 | move object to options. 26 | move "root" to user in options. 27 | move "" to password in options. 28 | move name in params in request to database in options. 29 | 30 | local connection. 31 | 32 | perform createConnection in mysql using options giving connection. 33 | 34 | perform query in connection using "show tables" showtables. 35 | 36 | showtables section using err, rows, fields. 37 | if err then 38 | display "

" err "

" 39 | stop run 40 | end-if. 41 | #> 42 | 43 | 44 | <# 45 | local k. 46 | local n. 47 | move length in rows to n. 48 | move 0 to k. 49 | local row. 50 | local text. 51 | local columnname. 52 | local databasename. 53 | move name in params in request to databasename. 54 | move "Tables_in_" to columnname. 55 | add databasename to columnname. 56 | 57 | perform varying k from 1 to n 58 | move rows(k) to row 59 | #> 60 | 61 | 62 | 63 | <# 64 | end-perform 65 | #> 66 |
Table
${row(columnname)}
67 | <# 68 | . 69 | stop run. 70 | #> 71 | -------------------------------------------------------------------------------- /samples/mysqlweb/databases.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 require. 5 | procedure division. 6 | #> 7 |

MySQL

8 |

Databases

9 | <# 10 | local mysql. 11 | 12 | perform require using "mysql" giving mysql. 13 | 14 | local options. 15 | local connection. 16 | 17 | move object to options. 18 | move "root" to user in options. 19 | move "" to password in options. 20 | 21 | perform createConnection in mysql using options giving connection. 22 | perform connect in connection. 23 | perform query in connection using "show databases" showdbs. 24 | 25 | showdbs section using err, rows, fields. 26 | if err then 27 | display "

" err "

" 28 | stop run 29 | end-if. 30 | #> 31 | 32 | 33 | <# 34 | local k. 35 | local n. 36 | move length in rows to n. 37 | move 0 to k. 38 | local row. 39 | 40 | perform varying k from 1 to n 41 | move rows(k) to row 42 | #> 43 | 44 | 45 | 46 | <# 47 | end-perform 48 | #> 49 |
Database
${Database in row}
50 | <# 51 | . 52 | stop run. 53 | #> 54 | 55 | -------------------------------------------------------------------------------- /samples/mysqlweb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mysql-web-example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "dependencies": { 6 | "mysql": "*" 7 | } 8 | } -------------------------------------------------------------------------------- /samples/mysqlweb/server.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), http = require('http'), url = require('url'), fs = require('fs'); function getPage(filename) { var program = cobs.compileTemplateFile(filename); return function (req, res) { program.run(cobs.getRuntime({ request: req, response: res, require: require })); } } var program = cobs.compileTemplateFile('./databases.cobp'); var mapping = {}; mapping['/'] = getPage('./databases.cobp'); mapping['/database'] = getPage('./database.cobp'); mapping['/table'] = getPage('./table.cobp'); // Tricky code, to review, put require in runtime global.require = require; http.createServer(function(req, res) { var requrl = url.parse(req.url, true); var page = mapping[requrl.pathname]; req.params = requrl.query; if (page) page(req,res); else { res.writeHead(404, { 'Content-type': 'text/plain' }); res.end("bad URL " + req.url); } }).listen(8000); console.log('Server started, listening at port 8000'); -------------------------------------------------------------------------------- /samples/mysqlweb/table.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 request. 5 | 02 response. 6 | 03 require. 7 | 8 | procedure division. 9 | local mysql. 10 | local tablename. 11 | local databasename. 12 | 13 | move name in params in request to tablename. 14 | move database in params in request to databasename. 15 | #> 16 |

Table ${tablename} in ${databasename}

17 |
18 | Databases 19 | Database 20 |
21 |

Columns

22 | <# 23 | 24 | perform require using "mysql" giving mysql. 25 | 26 | local options. 27 | 28 | move object to options. 29 | move "root" to user in options. 30 | move "" to password in options. 31 | move databasename to database in options. 32 | 33 | local connection. 34 | 35 | perform createConnection in mysql using options giving connection. 36 | 37 | local sql. 38 | 39 | move "show columns in " to sql. 40 | add tablename to sql. 41 | 42 | perform query in connection using sql showtables. 43 | 44 | showtables section using err, rows, fields. 45 | if err then 46 | display "

" err "

" 47 | stop run 48 | end-if. 49 | #> 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | <# 60 | local k. 61 | local n. 62 | move length in rows to n. 63 | local row. 64 | local text. 65 | local columnname. 66 | 67 | local defaultvalue. 68 | 69 | perform varying k from 1 to n 70 | move rows(k) to row 71 | if default in row then 72 | move default in row to defaultvalue 73 | else 74 | move "null" to defaultvalue 75 | end-if 76 | #> 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | <# 86 | end-perform. 87 | #> 88 |
FieldTypeNullKeyDefaultExtra
${Field in row}${Type in row}${Null in row}${Key in row}${defaultvalue}${Extra in row}
89 | <# 90 | . 91 | stop run. 92 | #> 93 | -------------------------------------------------------------------------------- /samples/template/README.md: -------------------------------------------------------------------------------- 1 | # Template Sample 2 | 3 | CobolScript code can be embedded in a text file. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | ## Run 10 | 11 | With the command line: 12 | 13 | ``` 14 | node run webserver.cobt 15 | ``` 16 | 17 | (actually, `.cobt` extension is reserved to template files). 18 | 19 | The template file: 20 | ``` 21 | <# 22 | data division. 23 | working-storage section. 24 | 01 n. 25 | 26 | procedure division. 27 | #> 28 | Factorial 29 | --------- 30 | 31 | <# 32 | perform show-factorial varying n from 1 to 10. 33 | 34 | show-factorial. 35 | local result. 36 | perform factorial using n giving result. 37 | #> 38 | ${n}!= ${result} 39 | <# 40 | . 41 | factorial using n. 42 | local m. 43 | if n = 1 then return n. 44 | subtract 1 from n giving m. 45 | perform factorial using m giving m. 46 | multiply n by m. 47 | return m. 48 | #> 49 | ``` 50 | 51 | CobolScript code is embedded between `<#` and `#>`. CobolScript expressions are embedded between `${` and `}`. 52 | 53 | -------------------------------------------------------------------------------- /samples/template/factorial.cobt: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | working-storage section. 4 | 01 n. 5 | 6 | procedure division. 7 | #> 8 | Factorial 9 | --------- 10 | 11 | <# 12 | perform show-factorial varying n from 1 to 10. 13 | 14 | show-factorial section. 15 | local result. 16 | perform factorial using n giving result. 17 | #> 18 | ${n}!= ${result} 19 | <# 20 | . 21 | factorial section using n. 22 | local m. 23 | if n = 1 then return n. 24 | subtract 1 from n giving m. 25 | perform factorial using m giving m. 26 | multiply n by m. 27 | return m. 28 | #> -------------------------------------------------------------------------------- /samples/template/run.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), fs = require('fs'); function runFile(filename) { cobs.compileTemplateFile(filename).run(cobs.getRuntime()); }; process.argv.forEach(function(val) { if (val.slice(-5) == ".cobt") runFile(val); }); -------------------------------------------------------------------------------- /samples/templateweb/README.md: -------------------------------------------------------------------------------- 1 | # Template Web Sample 2 | 3 | CobolScript code can be embedded in a text file, and it can be used to make a web page. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | ## Run 10 | 11 | With the command line: 12 | 13 | ``` 14 | node server 15 | ``` 16 | 17 | The output: 18 | ``` 19 | Server started, listening at port 8000 20 | ``` 21 | 22 | Then launch http://localhost:8000 in your browser. It works! 23 | 24 | ![Factorial Web Sample](https://raw.github.com/ajlopez/CobolScript/master/images/templateweb.png) 25 | 26 | The template file is `factorial.cobp` (actually, `.cobp` extension is reserved to this kind of web pages 27 | with templates): 28 | ``` 29 |

Factorial

30 |

Page generated by CobolScript, using templates

31 | 32 | 33 | <# 34 | local n. 35 | perform show-factorial using n varying n from 1 to 10. 36 | #> 37 |
nn!
38 | <# 39 | . 40 | 41 | show-factorial using n. 42 | local result. 43 | perform factorial using n giving result. 44 | #> 45 | ${n}${result} 46 | <# 47 | . 48 | 49 | factorial using n. 50 | local m. 51 | if n = 1 then return n. 52 | subtract 1 from n giving m. 53 | perform factorial using m giving m. 54 | multiply n by m. 55 | return m. 56 | #> 57 | ``` 58 | 59 | CobolScript code is embedded between `<#` and `#>`. CobolScript expressions are embedded between `${` and `}`. 60 | 61 | -------------------------------------------------------------------------------- /samples/templateweb/factorial.cobp: -------------------------------------------------------------------------------- 1 |

Factorial

2 |

Page generated by CobolScript, using templates

3 | 4 | 5 | <# 6 | local n. 7 | perform show-factorial using n varying n from 1 to 10. 8 | #> 9 |
nn!
10 | <# 11 | . 12 | stop run. 13 | 14 | show-factorial section using n. 15 | local result. 16 | perform factorial using n giving result. 17 | #> 18 | ${n}${result} 19 | <# 20 | . 21 | 22 | factorial section using n. 23 | local m. 24 | if n = 1 then return n. 25 | subtract 1 from n giving m. 26 | perform factorial using m giving m. 27 | multiply n by m. 28 | return m. 29 | #> 30 | 31 | -------------------------------------------------------------------------------- /samples/templateweb/server.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), http = require('http'), fs = require('fs'); var program = cobs.compileTemplateFile('./factorial.cobp'); http.createServer(function(req, res) { program.run(cobs.getRuntime({ request: req, response: res })); }).listen(8000); console.log('Server started, listening at port 8000'); -------------------------------------------------------------------------------- /samples/webserver/README.md: -------------------------------------------------------------------------------- 1 | # Web Server Sample 2 | 3 | Shows the use of Node.js modules. 4 | 5 | ## Setup 6 | 7 | Install [Node.js](http://nodejs.org). 8 | 9 | ## Run 10 | 11 | With the command line: 12 | 13 | ``` 14 | node run webserver.cob 15 | ``` 16 | 17 | Then launch 18 | http://localhost:8000 19 | in your browser. 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples/webserver/run.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../..'), fs = require('fs'); function runFile(filename) { cobs.compileProgramFile(filename).run(cobs.getRuntime({ require: require })); }; // Tricky, doing require global global.require = require; process.argv.forEach(function(val) { if (val.slice(-4) == ".cob") runFile(val); }); -------------------------------------------------------------------------------- /samples/webserver/webserver.cob: -------------------------------------------------------------------------------- 1 | data division. 2 | linkage section. 3 | 01 require. 4 | 5 | procedure division. 6 | local http. 7 | local server. 8 | 9 | perform require using "http" giving http. 10 | perform createServer in http using doget giving server. 11 | perform listen in server using 8000. 12 | display "listening on port 8000". 13 | 14 | doget section using request, response. 15 | perform write in response using "

Hello, world

". 16 | perform end in response. -------------------------------------------------------------------------------- /samples/website/README.md: -------------------------------------------------------------------------------- 1 | # Web Site Sample 2 | 3 | CobolScript can access MySQL server using a Node.js module, 4 | and listing databases, tables and columns in dynamic web pages. It uses Twitter bootstrap, and SimpleWeb middleware layer. 5 | 6 | ## Setup 7 | 8 | ### Node 9 | 10 | Install [Node.js](http://nodejs.org). 11 | 12 | Then, execute at command line: 13 | ``` 14 | npm install 15 | ``` 16 | This command installs the `mysql`, `simpleweb` modules, according to the dependecies described in `package.json` file. 17 | 18 | ### MySQL 19 | 20 | You must create a database `cobolscriptwebsite` in your MySQL database, and then execute the commands at `database.sql`. These 21 | commands defines the tables and initial data to be used by the sample. 22 | 23 | ## Run 24 | 25 | With the command line: 26 | ``` 27 | node server 28 | ``` 29 | 30 | The output: 31 | ``` 32 | Server started, listening at port 8000 33 | ``` 34 | 35 | The program connects to the MySQL server at localhost and list its database. The server must be running. 36 | 37 | In the pages, the code 38 | ``` 39 | perform require using "mysql" giving mysql. 40 | ``` 41 | loads the `mysql` module. 42 | 43 | Then 44 | ``` 45 | local options. 46 | 47 | move object to options. 48 | move "root" to user in options. 49 | move "" to password in options. 50 | move "cobolscriptwebsite" to database options. 51 | 52 | local connection. 53 | 54 | perform createConnection in mysql using options giving connection. 55 | ``` 56 | opens the connection. 57 | 58 | The code 59 | ``` 60 | perform query in connection using "select Id, Name, Address, Notes from customers order by Id" showcustomers. 61 | 62 | showcustomers section using err, rows, fields. 63 | * .... 64 | ``` 65 | pass `showcustomers` as a callback to asynchronous method `query` in `connection`. 66 | The callback accept three parameters: `err`, `rows`, `fields`. 67 | 68 | When the sql is an update command: 69 | ``` 70 | perform query in connection using "insert customers set Name = ?, Address = ?, Notes = ?" datavalues showcustomers. 71 | ``` 72 | then the callback receives two parameters: `err`, `result`. 73 | 74 | The `datavalues` parameters is an array, with the values to be passed to `?` placeholders. 75 | See [node-sql](https://github.com/felixge/node-mysql) for more detailed information. 76 | 77 | -------------------------------------------------------------------------------- /samples/website/database.sql: -------------------------------------------------------------------------------- 1 | 2 | -- Execute this file on database cobolscriptwebsite 3 | 4 | -- 5 | -- Table structure for table `customers` 6 | -- 7 | 8 | DROP TABLE IF EXISTS `customers`; 9 | CREATE TABLE IF NOT EXISTS `customers` ( 10 | `Id` int(11) NOT NULL AUTO_INCREMENT, 11 | `Name` varchar(200) DEFAULT NULL, 12 | `Address` text, 13 | `Notes` text, 14 | PRIMARY KEY (`Id`) 15 | ) TYPE=InnoDB; 16 | 17 | -- 18 | -- Dumping data for table `customers` 19 | -- 20 | 21 | INSERT INTO `customers` (`Id`, `Name`, `Address`, `Notes`) VALUES 22 | (1, 'Google', 'Address', 'Notes'); 23 | INSERT INTO `customers` (`Id`, `Name`, `Address`, `Notes`) VALUES 24 | (2, 'Apple', 'Address', 'Notes'); 25 | INSERT INTO `customers` (`Id`, `Name`, `Address`, `Notes`) VALUES 26 | (3, 'Microsoft', 'Address', 'Notes'); 27 | 28 | -- -------------------------------------------------------- 29 | 30 | -- 31 | -- Table structure for table `suppliers` 32 | -- 33 | 34 | DROP TABLE IF EXISTS `suppliers`; 35 | CREATE TABLE IF NOT EXISTS `suppliers` ( 36 | `Id` int(11) NOT NULL AUTO_INCREMENT, 37 | `Name` varchar(200) DEFAULT NULL, 38 | `Address` text, 39 | `Notes` text, 40 | PRIMARY KEY (`Id`) 41 | ) TYPE=InnoDB; 42 | 43 | INSERT INTO `suppliers` (`Id`, `Name`, `Address`, `Notes`) VALUES 44 | (1, 'Oracle', 'Address', 'Notes'); 45 | INSERT INTO `suppliers` (`Id`, `Name`, `Address`, `Notes`) VALUES 46 | (2, 'SAP', 'Address', 'Notes'); 47 | INSERT INTO `suppliers` (`Id`, `Name`, `Address`, `Notes`) VALUES 48 | (3, 'Salesforce', 'Address', 'Notes'); 49 | -------------------------------------------------------------------------------- /samples/website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website-example", 3 | "version": "0.0.1", 4 | "private": true, 5 | "dependencies": { 6 | "simpleweb": "0.0.1", 7 | "mysql": "*" 8 | } 9 | } -------------------------------------------------------------------------------- /samples/website/pages/customerDelete.cob: -------------------------------------------------------------------------------- 1 | data division. 2 | linkage section. 3 | 01 require. 4 | 01 request. 5 | 01 response. 6 | procedure division. 7 | local mysql. 8 | 9 | perform require using "mysql" giving mysql. 10 | 11 | local id. 12 | 13 | move id in query in request to id. 14 | 15 | local connection. 16 | 17 | perform delete-customer. 18 | 19 | delete-customer section. 20 | local options. 21 | move object to options. 22 | move "root" to user in options. 23 | move "" to password in options. 24 | move "cobolscriptwebsite" to database in options. 25 | 26 | perform createConnection in mysql using options giving connection. 27 | perform connect in connection. 28 | 29 | local datavalues. 30 | move array to datavalues. 31 | perform push in datavalues using id. 32 | 33 | perform query in connection using "delete from customers where Id = ?" datavalues delete-end. 34 | 35 | delete-end section using err, result. 36 | if err then 37 | display "Error". 38 | stop run. 39 | end-if. 40 | local headers. 41 | move object to headers. 42 | move "/customer" to headers("Location"). 43 | perform writeHead in response using 302 headers. 44 | perform end in connection. 45 | stop run. 46 | -------------------------------------------------------------------------------- /samples/website/pages/customerList.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 require. 5 | 01 response. 6 | 01 title. 7 | procedure division. 8 | move "Customers" to title. 9 | perform set-cache. 10 | #> 11 |

Customers

12 | 13 |
14 | New Customer 15 |
16 | 17 | <# 18 | local mysql. 19 | 20 | perform require using "mysql" giving mysql. 21 | 22 | local options. 23 | local connection. 24 | 25 | perform showpage. 26 | 27 | showpage section. 28 | move object to options. 29 | move "root" to user in options. 30 | move "" to password in options. 31 | move "cobolscriptwebsite" to database in options. 32 | 33 | perform createConnection in mysql using options giving connection. 34 | perform connect in connection. 35 | perform query in connection using "select Id, Name from customers order by Id" showcustomers. 36 | 37 | showcustomers section using err, rows, fields. 38 | if err then 39 | display "

" err "

" 40 | perform end in connection 41 | stop run 42 | end-if. 43 | #> 44 | 45 | 46 | <# 47 | local k. 48 | local n. 49 | move length in rows to n. 50 | move 0 to k. 51 | local row. 52 | 53 | perform varying k from 1 to n 54 | move rows(k) to row 55 | #> 56 | 57 | 58 | 59 | <# 60 | end-perform 61 | #> 62 |
Name
${Name in row}
63 | <# 64 | . 65 | perform end in connection. 66 | stop run. 67 | 68 | set-cache section. 69 | * Date in the past 70 | local headers. 71 | move object to headers. 72 | move "Mon, 20 Feb 1998 07:00:00 GMT" to headers("Expires"). 73 | local today. 74 | perform new in Date giving today. 75 | perform toString in today giving today. 76 | * Always modified 77 | move today to headers("Last-modified"). 78 | * HTTP/1.1 79 | move "no-cache, must-revalidate" to headers("Cache-control"). 80 | * HTTP/1.0 81 | move "no-cache" to headers("Pragma"). 82 | perform writeHead in response using 200 headers. 83 | #> 84 | 85 | -------------------------------------------------------------------------------- /samples/website/pages/customerNew.cob: -------------------------------------------------------------------------------- 1 | data division. 2 | linkage section. 3 | 01 require. 4 | 01 request. 5 | 01 response. 6 | procedure division. 7 | local mysql. 8 | 9 | perform require using "mysql" giving mysql. 10 | 11 | local name. 12 | local address. 13 | local notes. 14 | 15 | move name in body in request to name. 16 | move address in body in request to address. 17 | move notes in body in request to notes. 18 | 19 | local connection. 20 | 21 | perform insert-customer. 22 | 23 | insert-customer section. 24 | local options. 25 | move object to options. 26 | move "root" to user in options. 27 | move "" to password in options. 28 | move "cobolscriptwebsite" to database in options. 29 | 30 | perform createConnection in mysql using options giving connection. 31 | perform connect in connection. 32 | 33 | local datavalues. 34 | move array to datavalues. 35 | perform push in datavalues using name. 36 | perform push in datavalues using address. 37 | perform push in datavalues using notes. 38 | 39 | perform query in connection using "insert customers set Name = ?, Address = ?, Notes = ?" datavalues insert-end. 40 | 41 | insert-end section using err, result. 42 | if err then 43 | display "Error" 44 | stop run 45 | end-if. 46 | local location. 47 | move "/customer/view?id=" to location. 48 | add insertId in result to location. 49 | local headers. 50 | move object to headers. 51 | move location to headers("Location"). 52 | perform writeHead in response using 302 headers. 53 | perform end in connection. 54 | stop run. 55 | -------------------------------------------------------------------------------- /samples/website/pages/customerNew.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 require. 5 | 01 response. 6 | 01 title. 7 | procedure division. 8 | move "New Customer" to title. 9 | #> 10 |

New Customer

11 | 12 |
13 | Customers 14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
Name
Address
Notes
34 |
35 | <# 36 | stop run. 37 | #> 38 | 39 | -------------------------------------------------------------------------------- /samples/website/pages/customerUpdate.cob: -------------------------------------------------------------------------------- 1 | data division. 2 | linkage section. 3 | 01 require. 4 | 01 request. 5 | 01 response. 6 | procedure division. 7 | local mysql. 8 | 9 | perform require using "mysql" giving mysql. 10 | 11 | local name. 12 | local address. 13 | local notes. 14 | local id. 15 | 16 | move name in body in request to name. 17 | move address in body in request to address. 18 | move notes in body in request to notes. 19 | move id in body in request to id. 20 | 21 | local connection. 22 | 23 | perform insert-customer. 24 | 25 | insert-customer section. 26 | local options. 27 | move object to options. 28 | move "root" to user in options. 29 | move "" to password in options. 30 | move "cobolscriptwebsite" to database in options. 31 | 32 | perform createConnection in mysql using options giving connection. 33 | perform connect in connection. 34 | 35 | local datavalues. 36 | move array to datavalues. 37 | perform push in datavalues using name. 38 | perform push in datavalues using address. 39 | perform push in datavalues using notes. 40 | perform push in datavalues using id. 41 | 42 | perform query in connection using "update customers set Name = ?, Address = ?, Notes = ? where Id = ?" datavalues insert-end. 43 | 44 | insert-end section using err, result. 45 | if err then 46 | display "Error" 47 | stop run 48 | end-if. 49 | local location. 50 | move "/customer/view?id=" to location. 51 | add id to location. 52 | local headers. 53 | move object to headers. 54 | move location to headers("Location"). 55 | perform writeHead in response using 302 headers. 56 | perform end in connection. 57 | stop run. 58 | -------------------------------------------------------------------------------- /samples/website/pages/customerUpdate.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 require. 5 | 01 request. 6 | 01 title. 7 | procedure division. 8 | move "Update Customer" to title. 9 | local id. 10 | move id in query in request to id. 11 | #> 12 |

Update Customer

13 | 14 |
15 | Customers 16 | View 17 |
18 | 19 | <# 20 | local mysql. 21 | 22 | perform require using "mysql" giving mysql. 23 | 24 | local options. 25 | local connection. 26 | 27 | perform showpage. 28 | 29 | showpage section. 30 | move object to options. 31 | move "root" to user in options. 32 | move "" to password in options. 33 | move "cobolscriptwebsite" to database in options. 34 | 35 | perform createConnection in mysql using options giving connection. 36 | perform connect in connection. 37 | perform query in connection using "select Id, Name, Address, Notes from customers where Id = ?" id showcustomer. 38 | 39 | showcustomer section using err, rows, fields. 40 | if err then 41 | display "

" err "

" 42 | perform end in connection 43 | stop run 44 | end-if. 45 | local row. 46 | move rows(1) to row. 47 | #> 48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
Name
Address
Notes
66 | 67 |
68 | <# 69 | . 70 | perform end in connection. 71 | stop run. 72 | #> 73 | -------------------------------------------------------------------------------- /samples/website/pages/customerView.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 require. 5 | 01 request. 6 | 01 response. 7 | 01 title. 8 | procedure division. 9 | move "Customer" to title. 10 | perform set-cache. 11 | local id. 12 | move id in query in request to id. 13 | #> 14 |

Customer

15 | 16 |
17 | Customers 18 | Update 19 | Delete 20 |
21 | 22 | <# 23 | local mysql. 24 | 25 | perform require using "mysql" giving mysql. 26 | 27 | local options. 28 | local connection. 29 | 30 | perform showpage. 31 | 32 | showpage section. 33 | move object to options. 34 | move "root" to user in options. 35 | move "" to password in options. 36 | move "cobolscriptwebsite" to database in options. 37 | 38 | perform createConnection in mysql using options giving connection. 39 | perform connect in connection. 40 | perform query in connection using "select Id, Name, Address, Notes from customers where Id = ?" id showcustomer. 41 | 42 | showcustomer section using err, rows, fields. 43 | if err then 44 | display "

" err "

" 45 | perform end in connection 46 | stop run 47 | end-if. 48 | local row. 49 | move rows(1) to row. 50 | #> 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |
Id${Id in row}
Name${Name in row}
Address${Address in row}
Notes${Notes in row}
69 | <# 70 | . 71 | perform end in connection. 72 | stop run. 73 | 74 | set-cache section. 75 | * Date in the past 76 | local headers. 77 | move object to headers. 78 | move "Mon, 20 Feb 1998 07:00:00 GMT" to headers("Expires"). 79 | local today. 80 | perform new in Date giving today. 81 | perform toString in today giving today. 82 | * Always modified 83 | move today to headers("Last-modified"). 84 | * HTTP/1.1 85 | move "no-cache, must-revalidate" to headers("Cache-control"). 86 | * HTTP/1.0 87 | move "no-cache" to headers("Pragma"). 88 | perform writeHead in response using 200 headers. 89 | #> 90 | -------------------------------------------------------------------------------- /samples/website/pages/index.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 title. 5 | procedure division. 6 | move "Home" to title. 7 | #> 8 |

Home

9 |

Page generated by CobolScript, using templates

10 | <# 11 | stop run. 12 | #> -------------------------------------------------------------------------------- /samples/website/pages/layout.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 body. 5 | 01 title. 6 | procedure division. 7 | #> 8 | 9 | 10 | ${title} 11 | 12 | 13 | 14 | 15 | 16 | 38 | 39 |
40 | ${body} 41 |
42 | 43 | 44 | 45 | <# 46 | stop run. 47 | #> -------------------------------------------------------------------------------- /samples/website/pages/supplierDelete.cob: -------------------------------------------------------------------------------- 1 | data division. 2 | linkage section. 3 | 01 require. 4 | 01 request. 5 | 01 response. 6 | procedure division. 7 | local mysql. 8 | 9 | perform require using "mysql" giving mysql. 10 | 11 | local id. 12 | 13 | move id in query in request to id. 14 | 15 | local connection. 16 | 17 | perform delete-supplier. 18 | 19 | delete-supplier section. 20 | local options. 21 | move object to options. 22 | move "root" to user in options. 23 | move "" to password in options. 24 | move "cobolscriptwebsite" to database in options. 25 | 26 | perform createConnection in mysql using options giving connection. 27 | perform connect in connection. 28 | 29 | local datavalues. 30 | move array to datavalues. 31 | perform push in datavalues using id. 32 | 33 | perform query in connection using "delete from suppliers where Id = ?" datavalues delete-end. 34 | 35 | delete-end section using err, result. 36 | if err then 37 | display "Error". 38 | stop run. 39 | end-if. 40 | local headers. 41 | move object to headers. 42 | move "/supplier" to headers("Location"). 43 | perform writeHead in response using 302 headers. 44 | perform end in connection. 45 | stop run. 46 | -------------------------------------------------------------------------------- /samples/website/pages/supplierList.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 require. 5 | 01 response. 6 | 01 title. 7 | procedure division. 8 | move "Suppliers" to title. 9 | perform set-cache. 10 | #> 11 |

Suppliers

12 | 13 |
14 | New Supplier 15 |
16 | 17 | <# 18 | local mysql. 19 | 20 | perform require using "mysql" giving mysql. 21 | 22 | local options. 23 | local connection. 24 | 25 | perform showpage. 26 | 27 | showpage section. 28 | move object to options. 29 | move "root" to user in options. 30 | move "" to password in options. 31 | move "cobolscriptwebsite" to database in options. 32 | 33 | perform createConnection in mysql using options giving connection. 34 | perform connect in connection. 35 | perform query in connection using "select Id, Name from suppliers order by Id" showsuppliers. 36 | 37 | showsuppliers section using err, rows, fields. 38 | if err then 39 | display "

" err "

" 40 | perform end in connection 41 | stop run 42 | end-if. 43 | #> 44 | 45 | 46 | <# 47 | local k. 48 | local n. 49 | move length in rows to n. 50 | move 0 to k. 51 | local row. 52 | 53 | perform varying k from 1 to n 54 | move rows(k) to row 55 | #> 56 | 57 | 58 | 59 | <# 60 | end-perform 61 | #> 62 |
Name
${Name in row}
63 | <# 64 | . 65 | perform end in connection. 66 | stop run. 67 | 68 | set-cache section. 69 | * Date in the past 70 | local headers. 71 | move object to headers. 72 | move "Mon, 20 Feb 1998 07:00:00 GMT" to headers("Expires"). 73 | local today. 74 | perform new in Date giving today. 75 | perform toString in today giving today. 76 | * Always modified 77 | move today to headers("Last-modified"). 78 | * HTTP/1.1 79 | move "no-cache, must-revalidate" to headers("Cache-control"). 80 | * HTTP/1.0 81 | move "no-cache" to headers("Pragma"). 82 | perform writeHead in response using 200 headers. 83 | #> 84 | 85 | -------------------------------------------------------------------------------- /samples/website/pages/supplierNew.cob: -------------------------------------------------------------------------------- 1 | data division. 2 | linkage section. 3 | 01 require. 4 | 01 request. 5 | 01 response. 6 | procedure division. 7 | local mysql. 8 | 9 | perform require using "mysql" giving mysql. 10 | 11 | local name. 12 | local address. 13 | local notes. 14 | 15 | move name in body in request to name. 16 | move address in body in request to address. 17 | move notes in body in request to notes. 18 | 19 | local connection. 20 | 21 | perform insert-supplier. 22 | 23 | insert-supplier section. 24 | local options. 25 | move object to options. 26 | move "root" to user in options. 27 | move "" to password in options. 28 | move "cobolscriptwebsite" to database in options. 29 | 30 | perform createConnection in mysql using options giving connection. 31 | perform connect in connection. 32 | 33 | local datavalues. 34 | move array to datavalues. 35 | perform push in datavalues using name. 36 | perform push in datavalues using address. 37 | perform push in datavalues using notes. 38 | 39 | perform query in connection using "insert suppliers set Name = ?, Address = ?, Notes = ?" datavalues insert-end. 40 | 41 | insert-end section using err, result. 42 | if err then 43 | display "Error" 44 | stop run 45 | end-if. 46 | local location. 47 | move "/supplier/view?id=" to location. 48 | add insertId in result to location. 49 | local headers. 50 | move object to headers. 51 | move location to headers("Location"). 52 | perform writeHead in response using 302 headers. 53 | perform end in connection. 54 | stop run. 55 | -------------------------------------------------------------------------------- /samples/website/pages/supplierNew.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 require. 5 | 01 response. 6 | 01 title. 7 | procedure division. 8 | move "New Supplier" to title. 9 | #> 10 |

New Supplier

11 | 12 |
13 | Suppliers 14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
Name
Address
Notes
34 |
35 | <# 36 | stop run. 37 | #> 38 | 39 | -------------------------------------------------------------------------------- /samples/website/pages/supplierUpdate.cob: -------------------------------------------------------------------------------- 1 | data division. 2 | linkage section. 3 | 01 require. 4 | 01 request. 5 | 01 response. 6 | procedure division. 7 | local mysql. 8 | 9 | perform require using "mysql" giving mysql. 10 | 11 | local name. 12 | local address. 13 | local notes. 14 | local id. 15 | 16 | move name in body in request to name. 17 | move address in body in request to address. 18 | move notes in body in request to notes. 19 | move id in body in request to id. 20 | 21 | local connection. 22 | 23 | perform insert-supplier. 24 | 25 | insert-supplier section. 26 | local options. 27 | move object to options. 28 | move "root" to user in options. 29 | move "" to password in options. 30 | move "cobolscriptwebsite" to database in options. 31 | 32 | perform createConnection in mysql using options giving connection. 33 | perform connect in connection. 34 | 35 | local datavalues. 36 | move array to datavalues. 37 | perform push in datavalues using name. 38 | perform push in datavalues using address. 39 | perform push in datavalues using notes. 40 | perform push in datavalues using id. 41 | 42 | perform query in connection using "update suppliers set Name = ?, Address = ?, Notes = ? where Id = ?" datavalues insert-end. 43 | 44 | insert-end section using err, result. 45 | if err then 46 | display "Error" 47 | stop run 48 | end-if. 49 | local location. 50 | move "/supplier/view?id=" to location. 51 | add id to location. 52 | local headers. 53 | move object to headers. 54 | move location to headers("Location"). 55 | perform writeHead in response using 302 headers. 56 | perform end in connection. 57 | stop run. 58 | -------------------------------------------------------------------------------- /samples/website/pages/supplierUpdate.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 require. 5 | 01 request. 6 | 01 title. 7 | procedure division. 8 | move "Update Supplier" to title. 9 | local id. 10 | move id in query in request to id. 11 | #> 12 |

Update Supplier

13 | 14 |
15 | Suppliers 16 | View 17 |
18 | 19 | <# 20 | local mysql. 21 | 22 | perform require using "mysql" giving mysql. 23 | 24 | local options. 25 | local connection. 26 | 27 | perform showpage. 28 | 29 | showpage section. 30 | move object to options. 31 | move "root" to user in options. 32 | move "" to password in options. 33 | move "cobolscriptwebsite" to database in options. 34 | 35 | perform createConnection in mysql using options giving connection. 36 | perform connect in connection. 37 | perform query in connection using "select Id, Name, Address, Notes from suppliers where Id = ?" id showsupplier. 38 | 39 | showsupplier section using err, rows, fields. 40 | if err then 41 | display "

" err "

" 42 | perform end in connection 43 | stop run 44 | end-if. 45 | local row. 46 | move rows(1) to row. 47 | #> 48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
Name
Address
Notes
66 | 67 |
68 | <# 69 | . 70 | perform end in connection. 71 | stop run. 72 | #> 73 | -------------------------------------------------------------------------------- /samples/website/pages/supplierView.cobp: -------------------------------------------------------------------------------- 1 | <# 2 | data division. 3 | linkage section. 4 | 01 require. 5 | 01 request. 6 | 01 response. 7 | 01 title. 8 | procedure division. 9 | move "Supplier" to title. 10 | perform set-cache. 11 | local id. 12 | move id in query in request to id. 13 | #> 14 |

Supplier

15 | 16 |
17 | Suppliers 18 | Update 19 | Delete 20 |
21 | 22 | <# 23 | local mysql. 24 | 25 | perform require using "mysql" giving mysql. 26 | 27 | local options. 28 | local connection. 29 | 30 | perform showpage. 31 | 32 | showpage section. 33 | move object to options. 34 | move "root" to user in options. 35 | move "" to password in options. 36 | move "cobolscriptwebsite" to database in options. 37 | 38 | perform createConnection in mysql using options giving connection. 39 | perform connect in connection. 40 | perform query in connection using "select Id, Name, Address, Notes from suppliers where Id = ?" id showsupplier. 41 | 42 | showsupplier section using err, rows, fields. 43 | if err then 44 | display "

" err "

" 45 | perform end in connection 46 | stop run 47 | end-if. 48 | local row. 49 | move rows(1) to row. 50 | #> 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 |
Id${Id in row}
Name${Name in row}
Address${Address in row}
Notes${Notes in row}
69 | <# 70 | . 71 | perform end in connection. 72 | stop run. 73 | 74 | set-cache section. 75 | * Date in the past 76 | local headers. 77 | move object to headers. 78 | move "Mon, 20 Feb 1998 07:00:00 GMT" to headers("Expires"). 79 | local today. 80 | perform new in Date giving today. 81 | perform toString in today giving today. 82 | * Always modified 83 | move today to headers("Last-modified"). 84 | * HTTP/1.1 85 | move "no-cache, must-revalidate" to headers("Cache-control"). 86 | * HTTP/1.0 87 | move "no-cache" to headers("Pragma"). 88 | perform writeHead in response using 200 headers. 89 | #> 90 | -------------------------------------------------------------------------------- /samples/website/public/css/styles.css: -------------------------------------------------------------------------------- 1 | 2 | .view { 3 | min-width: 500px; 4 | } 5 | 6 | .view td { 7 | vertical-align: top; 8 | } 9 | 10 | .list { 11 | min-width: 500px; 12 | } 13 | 14 | .form { 15 | min-width: 500px; 16 | } 17 | 18 | .form td { 19 | vertical-align: top; 20 | } 21 | 22 | .content { 23 | margin: 10px; 24 | } 25 | 26 | .actions { 27 | margin-bottom: 20px; 28 | } 29 | 30 | .footer { 31 | margin: 10px; 32 | } -------------------------------------------------------------------------------- /samples/website/server.js: -------------------------------------------------------------------------------- 1 | 2 | var cobs = require('../..'); 3 | simpleweb = require('simpleweb'), 4 | path = require('path'), 5 | http = require('http'); 6 | 7 | var app = simpleweb(); 8 | 9 | app.use(simpleweb.query()); 10 | app.use(simpleweb.body()); 11 | app.use(app.router); 12 | app.use(simpleweb.static(path.join(__dirname, 'public'))); 13 | 14 | function makeTemplatePage(filename, layout) { 15 | var program = cobs.compileTemplateFile(filename); 16 | return function (req, res) { 17 | program.run(cobs.getRuntime({ request: req, response: res, require: require, layout: layout })); 18 | }; 19 | } 20 | 21 | function makePage(filename) { 22 | var program = cobs.compileProgramFile(filename); 23 | return function (req, res) { 24 | program.run(cobs.getRuntime({ request: req, response: res, require: require })); 25 | }; 26 | } 27 | 28 | function doMappings() { 29 | var layout = cobs.compileTemplateFile('./pages/layout.cobp'); 30 | app.get('/', makeTemplatePage('./pages/index.cobp', layout)); 31 | 32 | app.get('/customer', makeTemplatePage('./pages/customerList.cobp', layout)); 33 | app.get('/customer/new', makeTemplatePage('./pages/customerNew.cobp', layout)); 34 | app.post('/customer/new', makePage('./pages/customerNew.cob', layout)); 35 | app.get('/customer/update', makeTemplatePage('./pages/customerUpdate.cobp', layout)); 36 | app.post('/customer/update', makePage('./pages/customerUpdate.cob', layout)); 37 | app.get('/customer/delete', makePage('./pages/customerDelete.cob', layout)); 38 | app.get('/customer/view', makeTemplatePage('./pages/customerView.cobp', layout)); 39 | 40 | app.get('/supplier', makeTemplatePage('./pages/supplierList.cobp', layout)); 41 | app.get('/supplier/new', makeTemplatePage('./pages/supplierNew.cobp', layout)); 42 | app.post('/supplier/new', makePage('./pages/supplierNew.cob', layout)); 43 | app.get('/supplier/update', makeTemplatePage('./pages/supplierUpdate.cobp', layout)); 44 | app.post('/supplier/update', makePage('./pages/supplierUpdate.cob', layout)); 45 | app.get('/supplier/delete', makePage('./pages/supplierDelete.cob', layout)); 46 | app.get('/supplier/view', makeTemplatePage('./pages/supplierView.cobp', layout)); 47 | } 48 | 49 | doMappings(); 50 | 51 | app.get('/reload', function (req, res) { 52 | doMappings(); 53 | res.writeHead(302, { 'Location': '/' }); 54 | res.end(); 55 | }); 56 | 57 | var server = http.createServer(app).listen(8000); 58 | 59 | console.log('listening to http://localhost:8000'); 60 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Based on https://github.com/laverdet/node-fibers/blob/master/test.js 4 | 5 | var fs = require('fs'); 6 | var spawn = require('child_process').spawn; 7 | var path = require('path'); 8 | 9 | function runTest(test, cb) { 10 | var proc = spawn(process.execPath, [path.join('test', test)], {env: {NODE_PATH: __dirname}}); 11 | proc.stdout.setEncoding('utf8'); 12 | proc.stderr.setEncoding('utf8'); 13 | 14 | var stdout = '', stderr = ''; 15 | proc.stdout.on('data', function(data) { 16 | stdout += data; 17 | }); 18 | proc.stderr.on('data', function(data) { 19 | stderr += data; 20 | }); 21 | proc.stdin.end(); 22 | 23 | proc.on('exit', function(code) { 24 | if ((stdout !== 'pass\n' && stdout !== '') || stderr !== '') { 25 | return cb(new Error( 26 | 'Test `'+ test+ '` failed.\n'+ 27 | 'code: '+ code+ '\n'+ 28 | 'stderr: '+ stderr+ '\n'+ 29 | 'stdout: '+ stdout)); 30 | } 31 | console.log(test+ ': '+ 'pass'); 32 | cb(); 33 | }); 34 | } 35 | 36 | var cb = function(err) { 37 | if (err) { 38 | console.error(String(err)); 39 | process.exit(1); 40 | } 41 | }; 42 | fs.readdirSync('./test').reverse().forEach(function(file) { 43 | var stats = fs.lstatSync(path.join('./test',file)); 44 | if (!stats.isFile()) 45 | return; 46 | 47 | cb = new function(cb, file) { 48 | return function(err) { 49 | if (err) return cb(err); 50 | runTest(file, cb); 51 | }; 52 | }(cb, file); 53 | }); 54 | cb(); 55 | -------------------------------------------------------------------------------- /test/add.js: -------------------------------------------------------------------------------- 1 | 2 | var cobs = require('../'); 3 | 4 | function run(text, ws) { 5 | var program = cobs.compileProgram(text, ws); 6 | var data = program.run(null); 7 | return data.working_storage; 8 | }; 9 | 10 | exports['add 1 to variable'] = function (test) { 11 | var ws = { a: 1 }; 12 | var newws = run('add 1 to a.', ws); 13 | test.equal(newws.a, 2); 14 | } 15 | 16 | exports['add variable to variable'] = function (test) { 17 | var ws = { a: 1, b: 3 }; 18 | var newws = run('add b to a.', ws); 19 | test.equal(newws.a, 4); 20 | } 21 | 22 | exports['add two values with comma to variable'] = function (test) { 23 | var ws = { a: 1 }; 24 | var newws = run('add 2, 3 to a.', ws); 25 | test.equal(newws.a, 6); 26 | } 27 | 28 | exports['add two values to variable'] = function (test) { 29 | var ws = { a: 1 }; 30 | var newws = run('add 2 3 to a.', ws); 31 | test.equal(newws.a, 6); 32 | } 33 | 34 | exports['add two values to two variables'] = function (test) { 35 | var ws = { a: 1, b: 2 }; 36 | var newws = run('add 2 3 to a b.', ws); 37 | test.equal(newws.a, 6); 38 | test.equal(newws.b, 7); 39 | } 40 | 41 | exports['add two values to two variables with comma'] = function (test) { 42 | var ws = { a: 1, b: 2 }; 43 | var newws = run('add 2 3 to a, b.', ws); 44 | test.equal(newws.a, 6); 45 | test.equal(newws.b, 7); 46 | } 47 | 48 | exports['add two variables to variable'] = function (test) { 49 | var ws = { a: 1, b: 2, c: 3 }; 50 | var newws = run('add b c to a.', ws); 51 | test.equal(newws.a, 6); 52 | } 53 | 54 | exports['add with giving'] = function (test) { 55 | var ws = { a: 1, b: 2, c: 10 }; 56 | var newws = run('add a b giving c.', ws); 57 | test.equal(newws.a, 1); 58 | test.equal(newws.b, 2); 59 | test.equal(newws.c, 3); 60 | } 61 | 62 | exports['add with giving to two variables'] = function (test) { 63 | var ws = { a: 1, b: 2, c: 10, d: 11 }; 64 | var newws = run('add a b giving c d.', ws); 65 | test.equal(newws.a, 1); 66 | test.equal(newws.b, 2); 67 | test.equal(newws.c, 3); 68 | test.equal(newws.d, 3); 69 | } 70 | 71 | exports['add with giving to two variables with comma'] = function (test) { 72 | var ws = { a: 1, b: 2, c: 10, d: 11 }; 73 | var newws = run('add a b giving c, d.', ws); 74 | test.equal(newws.a, 1); 75 | test.equal(newws.b, 2); 76 | test.equal(newws.c, 3); 77 | test.equal(newws.d, 3); 78 | } 79 | 80 | -------------------------------------------------------------------------------- /test/compile.js: -------------------------------------------------------------------------------- 1 | 2 | var cobs = require('../'), 3 | path = require('path'); 4 | 5 | function compile(code, ws) { 6 | var program = cobs.compileProgram(code, ws); 7 | return program.compileText(); 8 | } 9 | 10 | function compileFile(filename, ws) { 11 | var program = cobs.compileProgramFile(filename, true); 12 | 13 | if (ws) { 14 | program.data = program.data || { }; 15 | program.data.working_storage = ws; 16 | } 17 | 18 | return program.compileText(); 19 | } 20 | 21 | exports['compile program defined'] = function (test) { 22 | test.ok(cobs.compileProgram); 23 | } 24 | 25 | exports['simple compile display'] = function (test) { 26 | var text = compile('display "hello".'); 27 | test.ok(text); 28 | test.ok(text.indexOf('runtime.display("hello");') >= 0); 29 | } 30 | 31 | exports['simple compile display from file'] = function (test) { 32 | var text = compileFile(path.join(__dirname, '/files/hello.cob')); 33 | test.ok(text); 34 | test.ok(text.indexOf('runtime.display("hello");') >= 0); 35 | } 36 | 37 | exports['display two values'] = function (test) { 38 | var text = compile('display "hello" "world".'); 39 | test.ok(text); 40 | test.ok(text.indexOf('runtime.display("hello", "world");') >= 0); 41 | } 42 | 43 | exports['display with advancing'] = function (test) { 44 | var text = compile('display "hello" "world" with advancing.'); 45 | test.ok(text); 46 | test.ok(text.indexOf('runtime.display("hello", "world");') >= 0); 47 | } 48 | 49 | exports['display with no advancing'] = function (test) { 50 | var text = compile('display "hello" "world" with no advancing.'); 51 | test.ok(text); 52 | test.ok(text.indexOf('runtime.write("hello", "world");') >= 0); 53 | } 54 | 55 | exports['display no advancing'] = function (test) { 56 | var text = compile('display "hello" "world" no advancing.'); 57 | test.ok(text); 58 | test.ok(text.indexOf('runtime.write("hello", "world");') >= 0); 59 | } 60 | 61 | exports['display two values comma separated'] = function (test) { 62 | var text = compile('display "hello", "world".'); 63 | test.ok(text); 64 | test.ok(text.indexOf('runtime.display("hello", "world");') >= 0); 65 | } 66 | 67 | exports['simple compile move'] = function (test) { 68 | var text = compile('move 1 to a-1.', {a_1: null}); 69 | test.ok(text); 70 | test.ok(text.indexOf('ws.a_1 = 1;') >= 0); 71 | } 72 | 73 | exports['compile simple variable'] = function (test) { 74 | text = compile('display A.', { a: null }); 75 | test.ok(text); 76 | test.ok(text.indexOf('runtime.display(ws.a);') >= 0); 77 | } 78 | 79 | exports['compile simple variable in program'] = function (test) { 80 | var text = compile('\ 81 | data division.\r\n\ 82 | working-storage section.\r\n\ 83 | 01 a.\r\n\ 84 | procedure division.\r\n\ 85 | display a.\r\n\ 86 | '); 87 | 88 | test.ok(text); 89 | test.ok(text.indexOf('runtime.display(ws.a);') >= 0); 90 | } 91 | 92 | exports['compile nested variable in program'] = function (test) { 93 | var text = compile('\ 94 | data division.\r\n\ 95 | working-storage section.\r\n\ 96 | 01 a.\r\n\ 97 | 02 b.\r\n\ 98 | procedure division.\r\n\ 99 | display b.\r\n\ 100 | '); 101 | test.ok(text); 102 | test.ok(text.indexOf('runtime.display(ws.a.b);') >= 0); 103 | } 104 | 105 | exports['simple compile two move commands'] = function (test) { 106 | var text = compile('move 1 to a-1. move 2 to a-2.', { a_1: null, a_2: null }); 107 | test.ok(text); 108 | test.ok(text.indexOf('ws.a_1 = 1;') >= 0); 109 | test.ok(text.indexOf('ws.a_2 = 2;') >= 0); 110 | } 111 | 112 | exports['simple compile two move commands without points'] = function (test) { 113 | var text = compile('move 1 to a-1 move 2 to a-2', { a_1: null, a_2: null }); 114 | test.ok(text); 115 | test.ok(text.indexOf('ws.a_1 = 1;') >= 0); 116 | test.ok(text.indexOf('ws.a_2 = 2;') >= 0); 117 | } 118 | 119 | exports['simple compile move to two variables'] = function (test) { 120 | var text = compile('move 1 to a-1, a-2.', { a_1: null, a_2: null }); 121 | test.ok(text); 122 | test.ok(text.indexOf('var $aux = 1; ws.a_1 = $aux; ws.a_2 = $aux;') >= 0); 123 | } 124 | 125 | exports['simple function'] = function (test) { 126 | var text = compile('procedure1 section.'); 127 | test.ok(text.indexOf('function procedure1()') >= 0); 128 | } 129 | 130 | exports['function with moves'] = function (test) { 131 | var text = compile('procedure1 section. move 1 to a. move 2 to b.', { a: null, b: null }); 132 | test.ok(text.indexOf('function procedure1() {') >= 0); 133 | test.ok(text.indexOf('ws.a = 1;') >= 0); 134 | test.ok(text.indexOf('ws.b = 2;') >= 0); 135 | test.ok(text.indexOf('}') >= 0); 136 | } 137 | 138 | exports['function with parameters'] = function (test) { 139 | var text = compile('procedure1 section using x, y. move x to a. move y to b.', { a: null, b: null }); 140 | test.ok(text.indexOf('function procedure1(x, y) {') >= 0); 141 | test.ok(text.indexOf('ws.a = x;') >= 0); 142 | test.ok(text.indexOf('ws.b = y;') >= 0); 143 | test.ok(text.indexOf('}') >= 0); 144 | } 145 | 146 | exports['if'] = function (test) { 147 | var text = compile('if a > 0 then move 0 to a.', { a: null }); 148 | test.ok(text.indexOf('if (ws.a > 0) {') >= 0); 149 | test.ok(text.indexOf('ws.a = 0;') >= 0); 150 | } 151 | 152 | exports['if with multiple commands'] = function (test) { 153 | var text = compile('if a > 0 then move 0 to a move 1 to b.', { a: null, b: null }); 154 | test.equal(text, 'if (ws.a > 0) { ws.a = 0; ws.b = 1; }'); 155 | } 156 | 157 | exports['if with else'] = function (test) { 158 | var text = compile('if a > 0 then move 0 to a else move 1 to b.', { a: null, b: null }); 159 | test.equal(text, 'if (ws.a > 0) { ws.a = 0; } else { ws.b = 1; }'); 160 | } 161 | 162 | exports['if with else end if'] = function (test) { 163 | var text = compile('if a > 0 then move 0 to a else move 1 to b end-if move 2 to c.', { a: null, b: null, c: null }); 164 | test.equal(text, 'if (ws.a > 0) { ws.a = 0; } else { ws.b = 1; } ws.c = 2;'); 165 | } 166 | 167 | exports['return with value'] = function (test) { 168 | var text = compile('return 1.'); 169 | test.ok(text.indexOf('return 1;') >= 0); 170 | } 171 | 172 | exports['return'] = function (test) { 173 | var text = compile('return.'); 174 | test.ok(text.indexOf('return;') >= 0); 175 | } 176 | 177 | exports['move to nested item'] = function (test) { 178 | var text = compile('move 0 to b in a', { a: { b: null } }); 179 | test.ok(text.indexOf('ws.a.b = 0;') >= 0); 180 | } 181 | 182 | exports['declare local variable'] = function (test) { 183 | var text = compile('local a.'); 184 | test.ok(text.indexOf('var a;') >= 0); 185 | } 186 | 187 | exports['declare and use local variable'] = function (test) { 188 | var text = compile('local a. move 1 to a'); 189 | test.ok(text.indexOf('var a;') >= 0); 190 | test.ok(text.indexOf('a = 1;') >= 0); 191 | } 192 | 193 | exports['declare two local variables'] = function (test) { 194 | var text = compile('locals a b.'); 195 | test.ok(text.indexOf('var a, b;') >= 0); 196 | } 197 | 198 | exports['declare and use global variable'] = function (test) { 199 | var text = compile('global a. move 1 to a'); 200 | test.ok(text.indexOf('var a;') < 0); 201 | test.ok(text.indexOf('a = 1;') >= 0); 202 | } 203 | 204 | exports['compile global invocation'] = function (test) { 205 | var text = compile('global foo. global require. perform require using "assert" giving foo.'); 206 | test.ok(text.indexOf('foo = require("assert");') >= 0); 207 | } 208 | 209 | exports['a linkage item is visible as a runtime field'] = function (test) { 210 | var text = compile('data division. linkage section. 01 a. procedure division. move 1 to a.'); 211 | test.ok(text.indexOf('runtime.a = 1;') >= 0); 212 | } 213 | 214 | exports['call a linkage item as procedure'] = function (test) { 215 | var text = compile('data division. linkage section. 01 response. procedure division. perform write in response.'); 216 | test.ok(text.indexOf('runtime.response.write()') >= 0); 217 | } 218 | 219 | exports['move an empty object'] = function (test) { 220 | var text = compile('local a. move object to a.'); 221 | test.ok(text.indexOf('a = {};') >= 0); 222 | } 223 | 224 | exports['move an empty array'] = function (test) { 225 | var text = compile('local a. move array to a.'); 226 | test.ok(text.indexOf('a = [];') >= 0); 227 | } 228 | 229 | exports['move to an indexed array by name'] = function (test) { 230 | var text = compile('local a. move 1 to a("foo")'); 231 | test.ok(text.indexOf('runtime.setIndex(a, "foo", 1);') >= 0); 232 | } 233 | 234 | exports['stop run'] = function (test) { 235 | var text = compile('stop run.'); 236 | test.equal(text, 'runtime.stop(0);'); 237 | } 238 | 239 | -------------------------------------------------------------------------------- /test/compileperform.js: -------------------------------------------------------------------------------- 1 | var cobs = require('../'), 2 | path = require('path'); 3 | 4 | function compile(code, ws) { 5 | var program = cobs.compileProgram(code, ws); 6 | return program.compileText(); 7 | } 8 | 9 | exports['function call with arguments'] = function (test) { 10 | var text = compile('perform procedure1 using a, b.', { a: null, b: null }); 11 | test.ok(text.indexOf('procedure1(ws.a, ws.b)') >= 0); 12 | }; 13 | 14 | exports['perform procedure'] = function (test) { 15 | var text = compile('perform procedure1.'); 16 | test.ok(text.indexOf('procedure1();') >= 0); 17 | }; 18 | 19 | exports['perform procedure with procedure'] = function (test) { 20 | var text = compile('perform procedure1. procedure1 section. move 1 to a. move 2 to b.', { a: null, b: null }); 21 | test.ok(text.indexOf('procedure1();') >= 0); 22 | test.ok(text.indexOf('function procedure1() {') >= 0); 23 | test.ok(text.indexOf('ws.a = 1;') >= 0); 24 | test.ok(text.indexOf('ws.b = 2;') >= 0); 25 | test.ok(text.indexOf('}') >= 0); 26 | }; 27 | 28 | exports['perform procedure with varying'] = function (test) { 29 | var text = compile('perform procedure1 varying k from 1 to 10 by 1. procedure1 section. move 1 to a. move 2 to b.', { k: null, a: null, b: null }); 30 | test.ok(text.indexOf('for (ws.k = 1; ws.k <= 10; ws.k++)') >= 0); 31 | test.ok(text.indexOf('procedure1();') >= 0); 32 | test.ok(text.indexOf('function procedure1() {') >= 0); 33 | test.ok(text.indexOf('ws.a = 1;') >= 0); 34 | test.ok(text.indexOf('ws.b = 2;') >= 0); 35 | test.ok(text.indexOf('}') >= 0); 36 | }; 37 | 38 | exports['perform procedure with giving'] = function (test) { 39 | var text = compile('perform procedure1 giving k. procedure1 section. return 1.', { k: null }); 40 | test.ok(text.indexOf('ws.k = procedure1();') >= 0); 41 | test.ok(text.indexOf('function procedure1() {') >= 0); 42 | test.ok(text.indexOf('return 1;') >= 0); 43 | test.ok(text.indexOf('}') >= 0); 44 | }; 45 | 46 | exports['perform procedure with giving many variables'] = function (test) { 47 | var text = compile('perform procedure-1 giving k, j. procedure-1 section. return 1.', { k: null, j: null }); 48 | test.ok(text.indexOf('var $aux = procedure_1();') >= 0); 49 | test.ok(text.indexOf('ws.k = $aux;') >= 0); 50 | test.ok(text.indexOf('ws.j = $aux;') >= 0); 51 | test.ok(text.indexOf('function procedure_1() {') >= 0); 52 | test.ok(text.indexOf('return 1;') >= 0); 53 | test.ok(text.indexOf('}') >= 0); 54 | }; 55 | 56 | exports['perform procedure with local'] = function (test) { 57 | var text = compile('\ 58 | procedure division.\r\n\ 59 | perform procedure-1.\r\n\ 60 | perform procedure-2.\r\n\ 61 | \r\n\ 62 | procedure-1 section. local a.\r\n\ 63 | move 1 to a.\r\n\ 64 | return a.\r\n\ 65 | \r\n\ 66 | procedure-2 section. local a.\r\n\ 67 | move 2 to a.\r\n\ 68 | return a.' 69 | , { k: null, j: null }); 70 | test.ok(text.indexOf('procedure_1();') >= 0); 71 | test.ok(text.indexOf('procedure_2();') >= 0); 72 | test.ok(text.indexOf('function procedure_1() {') >= 0); 73 | test.ok(text.indexOf('function procedure_2() {') >= 0); 74 | test.ok(text.indexOf('var a;') >= 0); 75 | test.ok(text.indexOf('}') >= 0); 76 | }; 77 | 78 | exports['perform with in'] = function (test) { 79 | var text = compile('perform func in obj'); 80 | test.ok(text.indexOf('obj.func()') >= 0); 81 | }; 82 | 83 | exports['use a procedure as parameter'] = function (test) { 84 | var text = compile('perform proc1 using proc2. proc1 section. return 1. proc2 section. return 2.'); 85 | test.ok(text.indexOf('proc1(proc2)') >= 0); 86 | }; 87 | 88 | exports['perform with async'] = function (test) { 89 | var text = compile('perform proc1 async. display "hello"'); 90 | test.equal(text, 'proc1($cb1); function $cb1() { runtime.display("hello"); }'); 91 | text = compile('perform proc1 async giving a. display "hello". display a'); 92 | test.equal(text, 'proc1($cb1); function $cb1(a) { runtime.display("hello"); runtime.display(a); }'); 93 | text = compile('perform proc1 async with error giving a. display "hello". display a'); 94 | test.equal(text, 'proc1($cb1); function $cb1(err, a) { runtime.display("hello"); runtime.display(a); }'); 95 | text = compile('perform proc1 async with error. perform proc2 async with error giving a. display "hello". display a'); 96 | test.equal(text, 'proc1($cb1); function $cb1(err) { proc2($cb2); function $cb2(err, a) { runtime.display("hello"); runtime.display(a); } }'); 97 | }; 98 | 99 | exports['procedure with async'] = function (test) { 100 | var text = compile('procedure division. local name. perform proc1 async giving name. display "hello " name. proc1 section async. return "world"'); 101 | test.equal(text, 'var name; proc1($cb1); function $cb1(name) { runtime.display("hello ", name); } function proc1($cb) { $cb("world"); return; }'); 102 | }; 103 | 104 | exports['perform inline'] = function (test) { 105 | var text = compile('local a. perform move 1 to a end-perform.'); 106 | test.equal(text, 'var a; while (true) { a = 1; }'); 107 | }; 108 | 109 | exports['perform inline with until'] = function (test) { 110 | var text = compile('local a. move 1 to a. perform until a > 10 add 1 to a end-perform.'); 111 | test.equal(text, 'var a; a = 1; while (!(a > 10)) { a = a + 1; }'); 112 | }; 113 | 114 | exports['perform inline with until with test first'] = function (test) { 115 | var text = compile('local a. move 1 to a. perform until a > 10 with test first add 1 to a end-perform.'); 116 | test.equal(text, 'var a; a = 1; while (!(a > 10)) { a = a + 1; }'); 117 | }; 118 | 119 | exports['perform inline with until with test last'] = function (test) { 120 | var text = compile('local a. move 1 to a. perform until a > 10 with test last add 1 to a end-perform.'); 121 | test.equal(text, 'var a; a = 1; while (true) { a = a + 1; if (!(a > 10)) break; }'); 122 | }; 123 | 124 | exports['perform inline with verying'] = function (test) { 125 | var text = compile('local a. local k. move 0 to a. perform varying k from 1 to 10 add k to a end-perform.'); 126 | test.equal(text, 'var a; var k; a = 0; for (k = 1; k <= 10; k += 1) { a = a + k; }'); 127 | 128 | var text = compile('local a. local k. local n. move 0 to a. move 10 to n. perform varying k from 1 to n add k to a end-perform.'); 129 | test.equal(text, 'var a; var k; var n; a = 0; n = 10; for (k = 1; k <= n; k += 1) { a = a + k; }'); 130 | }; 131 | 132 | exports['exit perform'] = function (test) { 133 | var text = compile('perform exit perform end-perform.'); 134 | test.equal(text, 'while (true) { break; }'); 135 | }; 136 | 137 | exports['compile new'] = function (test) { 138 | var text = compile('perform new in Date.'); 139 | test.equal(text, 'new Date();'); 140 | }; 141 | 142 | exports['compile new and giving'] = function (test) { 143 | var text = compile('local a. perform new in Date giving a.'); 144 | test.equal(text, 'var a; a = new Date();'); 145 | }; 146 | 147 | -------------------------------------------------------------------------------- /test/files/hello.cob: -------------------------------------------------------------------------------- 1 | display "hello". -------------------------------------------------------------------------------- /test/files/hello.cobt: -------------------------------------------------------------------------------- 1 | Hello ${a} World -------------------------------------------------------------------------------- /test/if.js: -------------------------------------------------------------------------------- 1 | 2 | var cobs = require('../'); 3 | 4 | function run(text, ws) { 5 | var program = cobs.compileProgram(text, ws); 6 | program.procedure = program.compileFunction(); 7 | var data = program.run(null); 8 | return data.working_storage; 9 | }; 10 | 11 | exports['simple if'] = function (test) { 12 | var ws = { a: 1 }; 13 | var newws = run('if a > 0 then move 0 to a.', ws); 14 | test.equal(newws.a, 0); 15 | }; 16 | 17 | exports['if with two commands'] = function (test) { 18 | var ws = { a: 1, b: 2 }; 19 | var newws = run('if a > 0 then move 0 to a move 1 to b.', ws); 20 | test.equal(newws.a, 0); 21 | test.equal(newws.b, 1); 22 | }; 23 | -------------------------------------------------------------------------------- /test/lexers.js: -------------------------------------------------------------------------------- 1 | 2 | var lexers = require('../lib/lexers'); 3 | 4 | var TokenType = lexers.TokenType; 5 | 6 | function getToken(text, value, type, test) 7 | { 8 | var lexer = lexers.createLexer(text); 9 | assertToken(lexer, value, type, test); 10 | test.equal(lexer.nextToken(), null); 11 | } 12 | 13 | function assertToken(lexer, value, type, test) 14 | { 15 | var token = lexer.nextToken(); 16 | test.ok(token); 17 | test.equal(token.value, value); 18 | test.equal(token.type, type); 19 | } 20 | 21 | exports['Lexer defined'] = function (test) { 22 | test.ok(lexers.createLexer); 23 | }; 24 | 25 | exports['Null token if null text'] = function (test) { 26 | var lexer = lexers.createLexer(null); 27 | 28 | test.equal(lexer.nextToken(), null); 29 | }; 30 | 31 | exports['Null token if empty text'] = function (test) { 32 | var lexer = lexers.createLexer(''); 33 | 34 | test.equal(lexer.nextToken(), null); 35 | }; 36 | 37 | exports['Get simple name'] = function (test) { 38 | var lexer = lexers.createLexer('DIVISION'); 39 | 40 | assertToken(lexer, 'DIVISION', TokenType.Name, test); 41 | 42 | test.equal(lexer.nextToken(), null); 43 | }; 44 | 45 | exports['Get simple name with spaces'] = function (test) { 46 | var lexer = lexers.createLexer(' DIVISION '); 47 | 48 | assertToken(lexer, 'DIVISION', TokenType.Name, test); 49 | 50 | test.equal(null, lexer.nextToken()); 51 | }; 52 | 53 | exports['Get simple name with digits'] = function (test) { 54 | var lexer = lexers.createLexer('ITEM01'); 55 | 56 | assertToken(lexer, 'ITEM01', TokenType.Name, test); 57 | 58 | test.equal(lexer.nextToken(), null); 59 | }; 60 | 61 | exports['Get two simple names'] = function (test) { 62 | var lexer = lexers.createLexer('IDENTIFICATION DIVISION'); 63 | 64 | assertToken(lexer, 'IDENTIFICATION', TokenType.Name, test); 65 | assertToken(lexer, 'DIVISION', TokenType.Name, test); 66 | 67 | test.equal(lexer.nextToken(), null); 68 | }; 69 | 70 | exports['Get name with minus sign'] = function (test) { 71 | var lexer = lexers.createLexer('WORKING-STORAGE'); 72 | 73 | assertToken(lexer, 'WORKING-STORAGE', TokenType.Name, test); 74 | 75 | test.equal(null, lexer.nextToken()); 76 | }; 77 | 78 | exports['Get integer number'] = function (test) { 79 | var lexer = lexers.createLexer('123'); 80 | 81 | assertToken(lexer, '123', TokenType.Integer, test); 82 | 83 | test.equal(null, lexer.nextToken()); 84 | }; 85 | 86 | exports['Get integer number with leading zeroes'] = function (test) { 87 | var lexer = lexers.createLexer('003'); 88 | 89 | assertToken(lexer, '003', TokenType.Integer, test); 90 | 91 | test.equal(lexer.nextToken(), null); 92 | }; 93 | 94 | exports['Get simple string'] = function (test) { 95 | getToken('"ADAM"', 'ADAM', TokenType.String, test); 96 | }; 97 | 98 | exports['Get simple string with quote'] = function (test) { 99 | getToken('"AD\\\"AM"', 'AD\\\"AM', TokenType.String, test); 100 | }; 101 | 102 | exports['Raise if unclosed string'] = function (test) { 103 | var lexer = lexers.createLexer('"ADAM'); 104 | 105 | test.throws( 106 | function() { 107 | assertToken(lexer, 'ADAM', TokenType.String, test); 108 | }, 109 | function(ex) { 110 | return ex == "unclosed string"; 111 | }); 112 | }; 113 | 114 | exports['Raise if unexpected character'] = function (test) { 115 | var lexer = lexers.createLexer('!'); 116 | 117 | test.throws( 118 | function() { 119 | assertToken(lexer, '!', TokenType.String, test); 120 | }, 121 | function(ex) { 122 | return ex == "unexpected '!'"; 123 | }); 124 | }; 125 | 126 | exports['Get point as Punctuation'] = function (test) { 127 | getToken('.', '.', TokenType.Punctuation, test); 128 | }; 129 | 130 | exports['Get comma as Punctuation'] = function (test) { 131 | getToken(',', ',', TokenType.Punctuation, test); 132 | }; 133 | 134 | exports['Get parenthesis as Punctuation'] = function (test) { 135 | getToken('(', '(', TokenType.Punctuation, test); 136 | getToken(')', ')', TokenType.Punctuation, test); 137 | }; 138 | 139 | exports['Skip line comment'] = function (test) { 140 | getToken('* This is a line comment \r\nDIVISION', 'DIVISION', TokenType.Name, test); 141 | }; 142 | 143 | exports['Skip two line comments'] = function (test) { 144 | getToken('* This is a line comment \r\n* This is another line comment \r\nDIVISION', 'DIVISION', TokenType.Name, test); 145 | }; 146 | 147 | exports['Get Phrase'] = function (test) { 148 | var lexer = lexers.createLexer("HELLO."); 149 | 150 | test.equal(lexer.nextPhrase(), "HELLO"); 151 | }; 152 | 153 | exports['Get Phrase with initial spaces and end of line'] = function (test) { 154 | var lexer = lexers.createLexer(" HELLO.\r\n"); 155 | 156 | test.equal(lexer.nextPhrase(), "HELLO"); 157 | }; 158 | 159 | exports['Get Phrase with inner points'] = function (test) { 160 | var lexer = lexers.createLexer("A.J.LOPEZ.\r\n"); 161 | 162 | test.equal(lexer.nextPhrase(), "A.J.LOPEZ"); 163 | }; 164 | 165 | exports['Get comparison operators'] = function (test) { 166 | getToken('<','<',TokenType.Operator, test); 167 | getToken('>','>',TokenType.Operator, test); 168 | getToken('=','=',TokenType.Operator, test); 169 | getToken('>=','>=',TokenType.Operator, test); 170 | getToken('<=','<=',TokenType.Operator, test); 171 | }; 172 | 173 | -------------------------------------------------------------------------------- /test/move.js: -------------------------------------------------------------------------------- 1 | 2 | var cobs = require('../'); 3 | 4 | function run(text, ws) { 5 | var program = cobs.compileProgram(text, ws); 6 | program.procedure = program.compileFunction(); 7 | var data = program.run(null); 8 | if (data) 9 | return data.working_storage; 10 | else 11 | return null; 12 | }; 13 | 14 | exports['compile and run move'] = function (test) { 15 | var ws = { a: null }; 16 | var newws = run('move 1 to a.', ws); 17 | test.equal(newws.a, 1); 18 | }; 19 | 20 | exports['compile and run two moves'] = function (test) { 21 | var ws = { a: null, b: null }; 22 | var newws = run('move 1 to a. move 2 to b.', ws); 23 | 24 | test.equal(newws.a, 1); 25 | test.equal(newws.b, 2); 26 | }; 27 | 28 | exports['compile and run two moves to nested items'] = function (test) { 29 | var ws = { 30 | group: { 31 | items: { 32 | a: null, 33 | b: null 34 | } 35 | } 36 | }; 37 | 38 | var newws = run('move 1 to a. move 2 to b.', ws); 39 | 40 | test.equal(newws.group.items.a, 1); 41 | test.equal(newws.group.items.b, 2); 42 | }; 43 | 44 | exports['compile and run move to two variables'] = function (test) { 45 | var ws = { a: null, b: null }; 46 | var newws = run('move 1 to a, b.', ws); 47 | 48 | test.equal(newws.a, 1); 49 | test.equal(newws.b, 1); 50 | }; 51 | 52 | -------------------------------------------------------------------------------- /test/parsers.js: -------------------------------------------------------------------------------- 1 | 2 | var parsers = require('../lib/parsers'); 3 | 4 | exports['Create parser defined'] = function (test) { 5 | test.ok(parsers.createParser); 6 | }; 7 | 8 | exports['Parse simple command'] = function (test) { 9 | var parser = parsers.createParser('DISPLAY "HELLO, WORLD".'); 10 | var cmd = parser.parseCommand(); 11 | test.ok(cmd); 12 | test.equal('runtime.display("HELLO, WORLD");', cmd.compile()); 13 | test.equal(null, parser.parseCommand()); 14 | }; 15 | 16 | exports['No point at end'] = function (test) { 17 | var parser = parsers.createParser('DISPLAY "HELLO, WORLD"'); 18 | var cmd = parser.parseCommand(); 19 | test.ok(cmd); 20 | test.equal('runtime.display("HELLO, WORLD");', cmd.compile()); 21 | test.equal(null, parser.parseCommand()); 22 | }; 23 | 24 | exports['Raise if extraneous char at end'] = function (test) { 25 | var parser = parsers.createParser('DISPLAY "HELLO, WORLD"!'); 26 | 27 | test.throws( 28 | function() { 29 | parser.parseCommand(); 30 | }, 31 | function(err) { 32 | return err == "unexpected '!'"; 33 | } 34 | ); 35 | }; 36 | 37 | exports['Parse Identification Division with Program Id'] = function (test) { 38 | var parser = parsers.createParser("\ 39 | IDENTIFICATION DIVISION.\r\n\ 40 | PROGRAM-ID. HELLO."); 41 | 42 | var program = parser.parseProgram(); 43 | 44 | test.ok(program); 45 | test.ok(program.identification); 46 | test.ok(program.identification.program_id); 47 | test.equal(program.identification.program_id, "HELLO"); 48 | }; 49 | 50 | exports['Parse commands'] = function (test) { 51 | var parser = parsers.createParser('display "hello". display "world".'); 52 | 53 | var commands = parser.parseCommands(); 54 | test.ok(commands); 55 | }; 56 | 57 | exports['Parse Identification Division'] = function (test) { 58 | var parser = parsers.createParser("\ 59 | IDENTIFICATION DIVISION.\r\n\ 60 | PROGRAM-ID. HELLO.\r\n\ 61 | AUTHOR. A.J.LOPEZ.\r\n\ 62 | INSTALLATION. TEST.\r\n\ 63 | DATE-WRITTEN. 2012-12-22.\r\n\ 64 | DATE-COMPILED. 2012-12-22.\r\n\ 65 | "); 66 | 67 | var program = parser.parseProgram(); 68 | 69 | test.ok(program); 70 | test.ok(program.identification); 71 | test.ok(program.identification.program_id); 72 | test.equal(program.identification.program_id, "HELLO"); 73 | test.equal(program.identification.author, "A.J.LOPEZ"); 74 | test.equal(program.identification.installation, "TEST"); 75 | test.equal(program.identification.date_written, "2012-12-22"); 76 | test.equal(program.identification.date_compiled, "2012-12-22"); 77 | }; 78 | 79 | exports['Parse Identification Division + Environment Division'] = function (test) { 80 | var parser = parsers.createParser("\ 81 | IDENTIFICATION DIVISION.\r\n\ 82 | PROGRAM-ID. HELLO.\r\n\ 83 | AUTHOR. A.J.LOPEZ.\r\n\ 84 | INSTALLATION. TEST.\r\n\ 85 | DATE-WRITTEN. 2012-12-22.\r\n\ 86 | DATE-COMPILED. 2012-12-22.\r\n\ 87 | ENVIRONMENT DIVISION.\r\n\ 88 | CONFIGURATION SECTION.\r\n\ 89 | SOURCE-COMPUTER. NODE.\r\n\ 90 | OBJECT-COMPUTER. NODE.\r\n\ 91 | "); 92 | 93 | var program = parser.parseProgram(); 94 | 95 | test.ok(program); 96 | test.ok(program.identification); 97 | test.ok(program.identification.program_id); 98 | test.equal(program.identification.program_id, "HELLO"); 99 | test.equal(program.identification.author, "A.J.LOPEZ"); 100 | test.equal(program.identification.installation, "TEST"); 101 | test.equal(program.identification.date_written, "2012-12-22"); 102 | test.equal(program.identification.date_compiled, "2012-12-22"); 103 | 104 | test.ok(program.environment); 105 | test.ok(program.environment.configuration); 106 | test.equal(program.environment.configuration.source_computer, "NODE"); 107 | test.equal(program.environment.configuration.object_computer, "NODE"); 108 | }; 109 | 110 | exports['Parse Identification Division + Environment Division + Empty Data Division + Procedure Division'] = function (test) { 111 | var parser = parsers.createParser('\ 112 | IDENTIFICATION DIVISION.\r\n\ 113 | PROGRAM-ID. HELLO.\r\n\ 114 | AUTHOR. A.J.LOPEZ.\r\n\ 115 | INSTALLATION. TEST.\r\n\ 116 | DATE-WRITTEN. 2012-12-22.\r\n\ 117 | DATE-COMPILED. 2012-12-22.\r\n\ 118 | ENVIRONMENT DIVISION.\r\n\ 119 | CONFIGURATION SECTION.\r\n\ 120 | SOURCE-COMPUTER. NODE.\r\n\ 121 | OBJECT-COMPUTER. NODE.\r\n\ 122 | DATA DIVISION.\r\n\ 123 | PROCEDURE DIVISION.\r\n\ 124 | DISPLAY "HELLO".\r\n\ 125 | '); 126 | 127 | var program = parser.parseProgram(); 128 | 129 | test.ok(program); 130 | test.ok(program.identification); 131 | test.ok(program.identification.program_id); 132 | test.equal(program.identification.program_id, "HELLO"); 133 | test.equal(program.identification.author, "A.J.LOPEZ"); 134 | test.equal(program.identification.installation, "TEST"); 135 | test.equal(program.identification.date_written, "2012-12-22"); 136 | test.equal(program.identification.date_compiled, "2012-12-22"); 137 | 138 | test.ok(program.environment); 139 | test.ok(program.environment.configuration); 140 | test.equal(program.environment.configuration.source_computer, "NODE"); 141 | test.equal(program.environment.configuration.object_computer, "NODE"); 142 | 143 | test.ok(program.data); 144 | test.ok(program.command); 145 | }; 146 | 147 | -------------------------------------------------------------------------------- /test/perform.js: -------------------------------------------------------------------------------- 1 | 2 | var cobs = require('../'); 3 | 4 | function run(text, ws) { 5 | var program = cobs.compileProgram(text, ws); 6 | program.procedure = program.compileFunction(); 7 | var data = program.run(cobs.getRuntime()); 8 | if (data) 9 | return data.working_storage; 10 | else 11 | return null; 12 | }; 13 | 14 | exports['perform procedure'] = function (test) { 15 | var ws = { a: 1 }; 16 | var newws = run('perform procedure1. procedure1 section. add 1 to a.', ws); 17 | test.equal(newws.a, 2); 18 | }; 19 | 20 | exports['perform procedure with two commands'] = function (test) { 21 | var ws = { a: 1, b: 3 }; 22 | var newws = run('perform procedure1. procedure1 section. add 1 to a. add 2 to b.', ws); 23 | test.equal(newws.a, 2); 24 | test.equal(newws.b, 5); 25 | }; 26 | 27 | exports['perform two procedures'] = function (test) { 28 | var ws = { a: 1, b: 3 }; 29 | var newws = run('perform procedure1. perform procedure2. procedure1 section. add 1 to a. procedure2 section. add 2 to b.', ws); 30 | test.equal(newws.a, 2); 31 | test.equal(newws.b, 5); 32 | }; 33 | 34 | exports['perform procedure 10 times'] = function (test) { 35 | var ws = { k: null, a: 0 }; 36 | var newws = run('perform procedure1 varying k from 1 to 4. procedure1 section. add k to a.', ws); 37 | test.equal(newws.a, 10); 38 | test.equal(newws.k, 5); 39 | }; 40 | 41 | exports['perform procedure passing argument'] = function (test) { 42 | var ws = { a: 1, b: 3 }; 43 | var newws = run('perform procedure1 using 3. procedure1 section using x. add x to a. add x to b.', ws); 44 | test.equal(newws.a, 4); 45 | test.equal(newws.b, 6); 46 | }; 47 | 48 | exports['perform procedure 10 times passing argument'] = function (test) { 49 | var ws = { k: null, a: 0 }; 50 | var newws = run('perform procedure1 using k varying k from 1 to 4. procedure1 section using x. add x to a.', ws); 51 | test.equal(newws.a, 10); 52 | test.equal(newws.k, 5); 53 | }; 54 | 55 | exports['perform with giving and return'] = function (test) { 56 | var ws = { result: 0 }; 57 | var newws = run('perform procedure1 using 3 giving result. procedure1 section using n. add 1 to n. return n.', ws); 58 | test.equal(newws.result, 4); 59 | }; 60 | 61 | exports['perform factorial with auxiliary parameters'] = function (test) { 62 | var ws = { result: 0 }; 63 | var newws = run('perform factorial using 3 giving result. factorial section using n. local m. if n = 1 then return n. subtract 1 from n giving m. perform factorial using m giving m. multiply n by m. return m.', ws); 64 | test.equal(newws.result, 6); 65 | }; 66 | 67 | exports['perform global function'] = function (test) { 68 | var result = 1; 69 | global.foo = function() { result = 2; }; 70 | 71 | var newws = run('global foo. perform foo.'); 72 | test.equal(result, 2); 73 | }; 74 | 75 | exports['invoke require'] = function (test) { 76 | global.foo = null; 77 | global.require = require; 78 | var assert = require('assert'); 79 | 80 | var newws = run('global foo. global require. perform require using "assert" giving foo.'); 81 | test.equal(global.foo, assert); 82 | }; 83 | 84 | exports['perform function in global object'] = function (test) { 85 | var result = 1; 86 | global.foo = { 87 | setresult: function(n) { result = n; } 88 | }; 89 | 90 | var newws = run('global foo. perform setresult in foo using 2.'); 91 | test.equal(result, 2); 92 | }; 93 | 94 | exports['perform Math cosine'] = function (test) { 95 | var ws = { result: null }; 96 | var newws = run('perform cos in Math using 10 giving result.', ws); 97 | test.ok(newws.result); 98 | test.equal(newws.result, Math.cos(10)); 99 | }; 100 | 101 | exports['perform inline perform'] = function (test) { 102 | var ws = { result: null }; 103 | var newws = run('local k. move 0 to result. perform varying k from 1 to 4 add k to result end-perform.', ws); 104 | test.ok(newws.result); 105 | test.equal(newws.result, 10); 106 | }; 107 | 108 | exports['perform inline perform with exit perform'] = function (test) { 109 | var ws = { result: null }; 110 | var newws = run('local k. move 0 to result. perform varying k from 1 to 4 add k to result if k >= 3 then exit perform end-perform.', ws); 111 | test.ok(newws.result); 112 | test.equal(newws.result, 6); 113 | }; 114 | 115 | exports['perform inline perform setting array values'] = function (test) { 116 | var ws = { a: [1, 2, 3, 4] }; 117 | var newws = run('local k. perform varying k from 1 to 4 add 1 to a(k) end-perform.', ws); 118 | test.ok(newws.a); 119 | test.equal(newws.a.toString(), '2,3,4,5'); 120 | 121 | var ws = { a: [0, 0, 0, 0], b: [0, 0, 0, 0] }; 122 | var newws = run('local k. perform varying k from 1 to 4 move k to a(k) b(k) end-perform.', ws); 123 | test.ok(newws.a); 124 | test.equal(newws.a.toString(), '1,2,3,4'); 125 | test.ok(newws.b); 126 | test.equal(newws.b.toString(), '1,2,3,4'); 127 | }; 128 | 129 | -------------------------------------------------------------------------------- /test/program.js: -------------------------------------------------------------------------------- 1 | 2 | var cobs = require('../'), 3 | path = require('path'); 4 | 5 | exports['compile program defined'] = function (test) { 6 | test.ok(cobs.compileProgram); 7 | }; 8 | 9 | exports['data division'] = function (test) { 10 | var program = cobs.compileProgram('data division.procedure division.return.'); 11 | test.ok(program); 12 | test.notEqual(typeof program.data, 'undefined'); 13 | }; 14 | 15 | exports['working-storage section'] = function (test) { 16 | var program = cobs.compileProgram('data division. working-storage section. procedure division.return.'); 17 | test.ok(program); 18 | test.ok(program.data); 19 | test.notEqual(typeof program.data.working_storage, 'undefined'); 20 | }; 21 | 22 | exports['linkage section'] = function (test) { 23 | var program = cobs.compileProgram('data division. linkage section. procedure division.return.'); 24 | test.ok(program); 25 | test.ok(program.data); 26 | test.notEqual(typeof program.data.linkage, 'undefined'); 27 | }; 28 | 29 | exports['linkage section with item'] = function (test) { 30 | var program = cobs.compileProgram('data division. linkage section. 01 request. 01 response. procedure division.return.'); 31 | test.ok(program); 32 | test.ok(program.data); 33 | test.ok(program.data.linkage); 34 | test.notEqual(typeof program.data.linkage.request, 'undefined'); 35 | test.notEqual(typeof program.data.linkage.response, 'undefined'); 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /test/run.js: -------------------------------------------------------------------------------- 1 | 2 | var cobs = require('../'); 3 | 4 | exports['compile and run display'] = function (test) { 5 | var program = cobs.compileProgram('display "Hello".'); 6 | 7 | var result = null; 8 | 9 | var runtime = { 10 | display: function(msg) { 11 | result = msg; 12 | } 13 | }; 14 | 15 | program.run(runtime); 16 | 17 | test.equal(result, "Hello"); 18 | }; 19 | 20 | exports['compile and run multiply 3 by variable'] = function (test) { 21 | var program = cobs.compileProgram('multiply 3 by a.', { a: 2 }); 22 | var data = program.run(null); 23 | test.equal(data.working_storage.a, 6); 24 | }; 25 | 26 | exports['compile and run divide 3 into variable'] = function (test) { 27 | var program = cobs.compileProgram('divide 3 into a.', { a: 6 }); 28 | var data = program.run(null); 29 | test.equal(data.working_storage.a, 2); 30 | }; 31 | -------------------------------------------------------------------------------- /test/runtime.js: -------------------------------------------------------------------------------- 1 | 2 | var cobs = require('../'); 3 | 4 | exports['getRuntime is defined'] = function (test) { 5 | test.ok(cobs.getRuntime); 6 | test.equal(typeof(cobs.getRuntime), 'function'); 7 | }; 8 | 9 | exports['getRuntime'] = function (test) { 10 | var runtime = cobs.getRuntime(); 11 | 12 | test.ok(runtime); 13 | test.ok(runtime.display); 14 | test.equal(typeof(runtime.display), 'function'); 15 | test.ok(runtime.write); 16 | test.equal(typeof(runtime.write), 'function'); 17 | test.ok(runtime.flush); 18 | test.equal(typeof(runtime.flush), 'function'); 19 | test.ok(runtime.getIndex); 20 | test.equal(typeof(runtime.getIndex), 'function'); 21 | test.ok(runtime.setIndex); 22 | test.equal(typeof(runtime.setIndex), 'function'); 23 | test.ok(runtime.global); 24 | }; 25 | 26 | exports['getRuntime with response, request, require'] = function (test) { 27 | var runtime = cobs.getRuntime( { response: {}, request: {}, require: require }); 28 | 29 | test.ok(runtime); 30 | test.ok(runtime.display); 31 | test.equal(typeof(runtime.display), 'function'); 32 | test.ok(runtime.write); 33 | test.equal(typeof(runtime.write), 'function'); 34 | test.ok(runtime.flush); 35 | test.equal(typeof(runtime.flush), 'function'); 36 | test.ok(runtime.getIndex); 37 | test.equal(typeof(runtime.getIndex), 'function'); 38 | test.ok(runtime.setIndex); 39 | test.equal(typeof(runtime.setIndex), 'function'); 40 | test.ok(runtime.response); 41 | test.ok(runtime.request); 42 | test.ok(runtime.global); 43 | test.ok(runtime.require); 44 | }; 45 | 46 | -------------------------------------------------------------------------------- /test/subtract.js: -------------------------------------------------------------------------------- 1 | 2 | var cobs = require('../'); 3 | 4 | function run(text, ws) { 5 | var program = cobs.compileProgram(text, ws); 6 | var data = program.run(null); 7 | return data.working_storage; 8 | }; 9 | 10 | exports['subtract 1 from variable'] = function (test) { 11 | var ws = { a: 1 }; 12 | var newws = run('subtract 1 from a.', ws); 13 | test.equal(ws.a, 1); 14 | test.equal(newws.a, 0); 15 | }; 16 | 17 | exports['subtract 1 from two variables'] = function (test) { 18 | var ws = { a: 1, b: 2 }; 19 | var newws = run('subtract 1 from a b.', ws); 20 | test.equal(ws.a, 1); 21 | test.equal(ws.b, 2); 22 | test.equal(newws.a, 0); 23 | test.equal(newws.b, 1); 24 | }; 25 | 26 | exports['subtract 1 from variable giving variable'] = function (test) { 27 | var ws = { a: 1, b: 2 }; 28 | var newws = run('subtract 1 from a giving b.', ws); 29 | test.equal(ws.a, 1); 30 | test.equal(ws.b, 2); 31 | test.equal(newws.a, 1); 32 | test.equal(newws.b, 0); 33 | }; 34 | 35 | exports['subtract 1 from variable giving to two variables'] = function (test) { 36 | var ws = { a: 1, b: 2, c: 3 }; 37 | var newws = run('subtract 1 from a giving b c.', ws); 38 | test.equal(newws.a, 1); 39 | test.equal(newws.b, 0); 40 | test.equal(newws.c, 0); 41 | }; 42 | 43 | exports['subtract 1 + 2 from variable giving to two variables'] = function (test) { 44 | var ws = { a: 1, b: 2, c: 3 }; 45 | var newws = run('subtract 1 2 from a giving b c.', ws); 46 | test.equal(newws.a, 1); 47 | test.equal(newws.b, -2); 48 | test.equal(newws.c, -2); 49 | }; 50 | 51 | -------------------------------------------------------------------------------- /test/template.js: -------------------------------------------------------------------------------- 1 | 2 | var cobs = require('../'), 3 | path = require('path'); 4 | 5 | function compile(text, ws) { 6 | var program = cobs.compileTemplate(text, true); 7 | 8 | if (ws) { 9 | program.data = program.data || { }; 10 | program.data.working_storage = ws; 11 | } 12 | 13 | return program.compileText(); 14 | } 15 | 16 | function compileFile(filename, ws) { 17 | var program = cobs.compileTemplateFile(filename, true); 18 | 19 | if (ws) { 20 | program.data = program.data || { }; 21 | program.data.working_storage = ws; 22 | } 23 | 24 | return program.compileText(); 25 | } 26 | 27 | exports['compileTemplate defined'] = function (test) { 28 | test.ok(cobs.compileTemplate); 29 | }; 30 | 31 | exports['compile simple text'] = function (test) { 32 | var text = compile("Hello"); 33 | test.ok(text.indexOf('runtime.write("Hello");') >= 0); 34 | }; 35 | 36 | exports['simple text with \r \n'] = function (test) { 37 | var text = compile("Hello\r\nWorld"); 38 | test.ok(text.indexOf('runtime.write("Hello\\r\\nWorld");') >= 0); 39 | }; 40 | 41 | exports['simple text with quotes'] = function (test) { 42 | var text = compile("Hello\"World\""); 43 | test.ok(text.indexOf('runtime.write("Hello\\\"World\\\"");') >= 0); 44 | }; 45 | 46 | exports['embedded code'] = function (test) { 47 | var text = compile("<# move 1 to a. #>", { a: null }); 48 | test.ok(text.indexOf("ws.a = 1;") >= 0); 49 | test.ok(text.indexOf("display") == -1); 50 | }; 51 | 52 | exports['text and embedded code'] = function (test) { 53 | var text = compile("Hello <# move 1 to a #> world", { a: null }); 54 | test.ok(text.indexOf("ws.a = 1;") >= 0); 55 | test.ok(text.indexOf('runtime.write("Hello ");') >= 0); 56 | test.ok(text.indexOf('runtime.write(" world");') >= 0); 57 | }; 58 | 59 | exports['text with expression'] = function (test) { 60 | var text = compile("Hello ${a}", { a: null }); 61 | test.ok(text.indexOf('runtime.write("Hello ", ws.a);') >= 0); 62 | }; 63 | 64 | exports['text with expression and text'] = function (test) { 65 | var text = compile("Hello ${a} World", { a: null }); 66 | test.ok(text.indexOf('runtime.write("Hello ", ws.a, " World");') >= 0); 67 | }; 68 | 69 | exports['text with expression and text from file'] = function (test) { 70 | var text = compileFile(path.join(__dirname, '/files/hello.cobt'), { a: null }); 71 | test.ok(text.indexOf('runtime.write("Hello ", ws.a, " World");') >= 0); 72 | }; 73 | 74 | -------------------------------------------------------------------------------- /test/ws.js: -------------------------------------------------------------------------------- 1 | 2 | var parsers = require('../lib/parsers'); 3 | 4 | exports['Working storage with one variable'] = function (test) { 5 | var parser = parsers.createParser('\ 6 | DATA DIVISION.\r\n\ 7 | WORKING-STORAGE SECTION.\r\n\ 8 | 01 ITEM.\r\n\ 9 | '); 10 | 11 | var program = parser.parseProgram(); 12 | 13 | test.ok(program); 14 | test.ok(program.data); 15 | test.ok(program.data.working_storage); 16 | test.ok(typeof(program.data.working_storage.item) != 'undefined'); 17 | }; 18 | 19 | exports['Working storage with two variables'] = function (test) { 20 | var parser = parsers.createParser('\ 21 | DATA DIVISION.\r\n\ 22 | WORKING-STORAGE SECTION.\r\n\ 23 | 01 ITEM1.\r\n\ 24 | 01 ITEM2.\r\n\ 25 | '); 26 | 27 | var program = parser.parseProgram(); 28 | 29 | test.ok(program); 30 | test.ok(program.data); 31 | test.ok(program.data.working_storage); 32 | test.ok(typeof(program.data.working_storage.item1) != 'undefined'); 33 | test.ok(typeof(program.data.working_storage.item2) != 'undefined'); 34 | }; 35 | 36 | exports['Working storage with group item and two subitems'] = function (test) { 37 | var parser = parsers.createParser('\ 38 | DATA DIVISION.\r\n\ 39 | WORKING-STORAGE SECTION.\r\n\ 40 | 01 GROUP1.\r\n\ 41 | 02 ITEM1.\r\n\ 42 | 02 ITEM2.\r\n\ 43 | '); 44 | 45 | var program = parser.parseProgram(); 46 | 47 | test.ok(program); 48 | test.ok(program.data); 49 | test.ok(program.data.working_storage); 50 | test.ok(typeof(program.data.working_storage.group1) != 'undefined'); 51 | test.ok(typeof(program.data.working_storage.group1.item1) != 'undefined'); 52 | test.ok(typeof(program.data.working_storage.group1.item2) != 'undefined'); 53 | }; 54 | 55 | exports['Working storage with two group items and three levels'] = function (test) { 56 | var parser = parsers.createParser('\ 57 | DATA DIVISION.\r\n\ 58 | WORKING-STORAGE SECTION.\r\n\ 59 | 01 GROUP1.\r\n\ 60 | 02 ITEM1.\r\n\ 61 | 03 SUBITEM1.\r\n\ 62 | 03 SUBITEM2.\r\n\ 63 | 02 ITEM2.\r\n\ 64 | 01 GROUP2.\r\n\ 65 | 02 ITEM1.\r\n\ 66 | 02 ITEM2.\r\n\ 67 | '); 68 | 69 | var program = parser.parseProgram(); 70 | 71 | test.ok(program); 72 | test.ok(program.data); 73 | test.ok(program.data.working_storage); 74 | test.ok(program.data.working_storage.group1); 75 | test.ok(program.data.working_storage.group1.item1); 76 | test.ok(typeof(program.data.working_storage.group1.item1.subitem1) != 'undefined'); 77 | test.ok(typeof(program.data.working_storage.group1.item1.subitem2) != 'undefined'); 78 | test.ok(typeof(program.data.working_storage.group1.item2) != 'undefined'); 79 | test.ok(program.data.working_storage.group2); 80 | test.ok(typeof(program.data.working_storage.group2.item1) != 'undefined'); 81 | test.ok(typeof(program.data.working_storage.group2.item2) != 'undefined'); 82 | }; 83 | 84 | --------------------------------------------------------------------------------