├── tests ├── truth-machine.lgc ├── all_logic_gates.lgc ├── length.lgc ├── square.lgc └── primality_tester.lgc ├── syntax ├── lgc.vim └── Logicode.sublime-syntax ├── LICENSE ├── README.md ├── test.py └── logicode.py /tests/truth-machine.lgc: -------------------------------------------------------------------------------- 1 | circ r(a)->r(a) 2 | cond 0->out r(1)/out 0 3 | -------------------------------------------------------------------------------- /tests/all_logic_gates.lgc: -------------------------------------------------------------------------------- 1 | circ g1()->0 2 | circ g2(a,b)->a&b 3 | circ g3(a,b)->a&(!b) 4 | circ g4(a)->a 5 | circ g5(a,b)->(!a)&b 6 | circ g6(a,b)->b 7 | circ g7(a,b)->(!(a&b))&(a|b) 8 | circ g8(a,b)->a|b 9 | circ g9(a,b)->!(a|b) 10 | circ g10(a,b)->!((!(a&b))&(a|b)) 11 | circ g11(a,b)->!b 12 | circ g12(a,b)->(!a)|b 13 | circ g13(a)->!a 14 | circ g14(a,b)->a|(!b) 15 | circ g15(a,b)->!(a,b) 16 | circ g16()->1 17 | -------------------------------------------------------------------------------- /tests/length.lgc: -------------------------------------------------------------------------------- 1 | circ trim(n) -> [ 2 | cond n< -> var trimout = 0 + n / var trimout = trim(n>) 3 | trimout 4 | ] 5 | circ successor(n) -> [ 6 | cond n -> var temp = ~((~(trim(n)))>) / var temp = 0 7 | cond (~n)< -> var succout = successor(temp) + 0 / var succout = temp + 1 8 | succout 9 | ] 10 | circ length(n) -> [ 11 | cond n -> var length_digit = successor(length_digit) / var string = n 12 | cond n -> var string = length(~((~n)>)) / var string = n 13 | length_digit> 14 | ] 15 | var string = trim(binp) 16 | var length_digit = 0 17 | out length(string) 18 | -------------------------------------------------------------------------------- /syntax/lgc.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file for Logicode 2 | " https://github.com/LogicodeLang/Logicode 3 | " Author: TuxCrafting 4 | " 5 | " Installation instructions: 6 | " 1. Copy this file to ~/.vim/syntax/lgc.vim 7 | " 2. Create the file ~/.vim/ftdetect/lgc.vim 8 | " 3. Write 'au BufRead,BufNewFile *.lgc set filetype=lgc' in the ftdetect file 9 | " 4. ??? 10 | " 5. Profit! 11 | 12 | if exists("b:current_syntax") 13 | finish 14 | endif 15 | 16 | syn keyword lgcTodo TODO FIXME XXX NOTE 17 | syn match lgcComment "#.*$" contains=lgcTodo 18 | syn keyword lgcKeyword circ cond out var 19 | syn match lgcNumber "[01]\+" 20 | 21 | let b:current_syntax = "lgc" 22 | 23 | hi def link lgcTodo Todo 24 | hi def link lgcComment Comment 25 | hi def link lgcKeyword Statement 26 | hi def link lgcNumber Constant 27 | -------------------------------------------------------------------------------- /tests/square.lgc: -------------------------------------------------------------------------------- 1 | circ trim(n) -> [ 2 | cond n< -> var trimout = 0 + n / var trimout = trim(n>) 3 | trimout 4 | ] 5 | circ successor(n) -> [ 6 | cond n -> var succtemp = ~((~(trim(n)))>) / var succtemp = 0 7 | cond (~n)< -> var succout = successor(succtemp) + 0 / var succout = succtemp + 1 8 | succout 9 | ] 10 | circ antisucc(n) -> [ 11 | cond n -> var antitemp = ~((~(trim(n)))>) / var antitemp = 0 12 | cond (~n)< -> var antiout = antitemp + 0 / var antiout = antisucc(antitemp) + 1 13 | antiout 14 | ] 15 | circ add(a, b) -> [ 16 | var addtemp = a 17 | cond b -> var addtemp = add(successor(addtemp), antisucc(b)) / var addtemp = addtemp 18 | addtemp 19 | ] 20 | circ sub(a, b) -> [ 21 | var subtemp = a 22 | cond b -> var subtemp = sub(antisucc(subtemp), antisucc(b)) / var subtemp = subtemp 23 | subtemp 24 | ] 25 | circ mult(a, b) -> [ 26 | var multtemp = a 27 | cond b -> var multtemp = add(mult(a, antisucc(b)), a) / var multtemp = sub(multtemp, a) 28 | multtemp 29 | ] 30 | circ square(a) -> mult(a, a) 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 LogicodeLang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/primality_tester.lgc: -------------------------------------------------------------------------------- 1 | circ bool(n) -> [ 2 | cond n -> var boolout = 1 / var boolout = 0 3 | boolout 4 | ] 5 | circ trim(n) -> [ 6 | cond n< -> var trimout = 0 + n / var trimout = trim(n>) 7 | trimout 8 | ] 9 | circ successor(n) -> [ 10 | cond n -> var succtemp = ~((~(trim(n)))>) / var succtemp = 0 11 | cond (~n)< -> var succout = successor(succtemp) + 0 / var succout = succtemp + 1 12 | succout 13 | ] 14 | circ antisucc(n) -> [ 15 | cond n -> var antitemp = ~((~(trim(n)))>) / var antitemp = 0 16 | cond (~n)< -> var antiout = antitemp + 0 / var antiout = antisucc(antitemp) + 1 17 | antiout 18 | ] 19 | circ modsub(a, b) -> [ 20 | cond bool(a)&bool(b) -> var subtemp = modsub(antisucc(a), antisucc(b)) / var subtemp = a 21 | subtemp 22 | ] 23 | circ lessthan(a, b) -> !(bool(modsub(b, a))) 24 | circ sub(a, b) -> [ 25 | cond b -> var subtemp = sub(antisucc(a), antisucc(b)) / var subtemp = a 26 | subtemp 27 | ] 28 | circ modcheck(a, b) -> [ 29 | cond lessthan(a, b) -> var modout = modcheck(sub(a, b), b) / var modout = !(bool(a)) 30 | modout 31 | ] 32 | circ isprime(a) -> [ 33 | var primecheck = successor(primecheck) 34 | cond lessthan(a, primecheck) -> var primeout = primeout + modcheck(a, primecheck) / var primeout = primeout 35 | cond lessthan(a, primecheck) -> var filler = isprime(a) / var primeout = primeout 36 | !(bool((~primeout)>)) 37 | ] 38 | var primecheck = 1 39 | var primeout = 0 40 | out isprime(binp) 41 | -------------------------------------------------------------------------------- /syntax/Logicode.sublime-syntax: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | --- 3 | # See http://www.sublimetext.com/docs/3/syntax.html 4 | file_extensions: 5 | - lgc 6 | scope: source 7 | variables: 8 | identifier: ((?!\binput\b|\b__scope__\b)[a-zA-Z_$]+) 9 | contexts: 10 | main: 11 | - match: (\#) 12 | scope: punctuation.definition.comment 13 | push: comment 14 | 15 | - match: \b(circ)\b 16 | scope: keyword.control 17 | push: circ 18 | 19 | - match: \b(cond)\b 20 | scope: keyword.control 21 | push: cond 22 | 23 | - match: \b(out)\b 24 | scope: keyword.control 25 | push: out 26 | 27 | - match: \b(var)\b 28 | scope: storage.type 29 | push: var 30 | 31 | - match: \b(input|__scope__)\b 32 | scope: keyword.control 33 | 34 | - match: (->) 35 | scope: storage.type 36 | 37 | - match: ([&|!<>$=/]) 38 | scope: keyword.operator 39 | 40 | - match: ({{identifier}}(?=\()) 41 | scope: entity.name.function 42 | 43 | - include: literal 44 | 45 | literal: 46 | - match: \b([01]+)\b 47 | scope: constant.numeric 48 | 49 | - match: (\?) 50 | scope: constant 51 | 52 | comment: 53 | - meta_scope: comment.line 54 | - match: $ 55 | pop: true 56 | 57 | circ: 58 | - match: ( +) 59 | set: circ2 60 | 61 | circ2: 62 | - match: \b{{identifier}}\b 63 | scope: entity.name.function 64 | set: circ3 65 | 66 | circ3: 67 | - match: (\() 68 | set: arguments 69 | 70 | arguments: 71 | - match: \b{{identifier}}\b 72 | scope: variable.parameter.function 73 | set: arguments_alpha 74 | - match: (\)) 75 | pop: true 76 | 77 | arguments_alpha: 78 | - match: (,[ \t]*) 79 | set: arguments 80 | - match: (\)) 81 | pop: true 82 | 83 | cond: 84 | - match: ( +) 85 | pop: true 86 | 87 | out: 88 | - match: ( +) 89 | pop: true 90 | 91 | var: 92 | - match: ( +) 93 | pop: true 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Logicode 2 | Welcome to Logicode! 3 | 4 | Logicode is a minimalistic language that is mainly based on Logisim. 5 | 6 | Because of that, the only built-in commands are AND, OR and NOT, and you make the rest. 7 | 8 | The three logic gates are represented like so: 9 | 10 | - `a&b`: AND of `a` and `b`. 11 | - `a|b`: OR of `a` and `b`. 12 | - `!a`: NOT of `a`. 13 | 14 | There are more built-ins: 15 | 16 | - `?`: Random bit, either `0` or `1`. 17 | - `#`: Begins a line for comments. 18 | 19 | You can make extra things from these commands, like circuits and variables. 20 | 21 | ## Make-your-own Things 22 | 23 | ### Circuits 24 | To create a circuit, you have to do this: 25 | 26 | `circ circuit_name(arg1, arg2...)->{what the function does}` 27 | 28 | `circ` is the circuit "declaration", and everything after the `->` is interpreted as code. 29 | 30 | Normal circuits have 1 bit as output, but if more bits are required, use the `+` symbol to separate bits. 31 | 32 | Like this: 33 | 34 | `circ circuit_name(arg1, arg2...)->{1st bit}+{2nd bit}+...` 35 | 36 | ### Variables 37 | To create a variable: 38 | 39 | `var var_name=value` 40 | 41 | `var` is the variable declaration. 42 | 43 | ### Conditions 44 | To create a condition: 45 | 46 | `cond arg->{executed if arg = 1}/{executed if arg = 0}` 47 | 48 | `cond` is the variable declaration, `arg` is either a value of `0` or `1`, and the `/` is the separator of the two executing strings. 49 | 50 | ## I/O 51 | 52 | ### Output 53 | There is also output as well: 54 | 55 | `out out_value` 56 | 57 | `out` is the output declaration, and you can include the built-in commands, as well as self-made circuits, into the output to be processed. 58 | 59 | ## Example code: 60 | 61 | circ xor(a,b)->(!(a&b))&(a|b) 62 | var test=xor(1,1) 63 | out !(test) 64 | 65 | Output: 1 66 | 67 | The circuit `xor` calculates the XOR of two bits, and `test` is declared as the XOR of 1 and 1 (which is 0). 68 | 69 | Then, the `out` outputs the NOT of `test`, which is `1`. 70 | 71 | Expanding on the previous example: 72 | 73 | circ xor(a,b)->(!(a&b))&(a|b) 74 | circ ha(a,b)->(a&b)+(xor(a,b)) 75 | out ha(1,?) 76 | 77 | Output: 10 78 | 79 | The circuit `xor` is the same as before, and the circuit `ha` is a half-adder of two bits (so it takes two arguments), and outputs two bits. 80 | 81 | The `out` outputs the half-adding of `1` and `?`, which is either `01` or `10` (depending on what the `?` gives). 82 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | from logicode import Run 2 | import unittest 3 | import sys 4 | 5 | class Test(unittest.TestCase): 6 | def test_and(self): 7 | self.assertEqual(Run("1&1"), [1]) 8 | self.assertEqual(Run("1&0"), [0]) 9 | self.assertEqual(Run("0&1"), [0]) 10 | self.assertEqual(Run("0&0"), [0]) 11 | 12 | def test_or(self): 13 | self.assertEqual(Run("1|1"), [1]) 14 | self.assertEqual(Run("1|0"), [1]) 15 | self.assertEqual(Run("0|1"), [1]) 16 | self.assertEqual(Run("0|0"), [0]) 17 | 18 | def test_not(self): 19 | self.assertEqual(Run("!1"), [0]) 20 | self.assertEqual(Run("!0"), [1]) 21 | 22 | def test_plus(self): 23 | self.assertEqual(Run("1+1"), [1, 1]) 24 | self.assertEqual(Run("1&1&1&1+1&1&1&1"), [1, 1]) 25 | 26 | def test_ascii(self): 27 | self.assertEqual(Run("@1001000"), ["H"]) 28 | self.assertEqual(Run("@111111+@111111"), ["?", "?"]) 29 | 30 | def test_reverse(self): 31 | self.assertEqual(Run("~1"), [1]) 32 | self.assertEqual(Run("~0101"), [1, 0, 1, 0]) 33 | 34 | def test_heads_tails(self): 35 | self.assertEqual(Run("100>>"), [0]) 36 | self.assertEqual(Run("100>"), [0, 0]) 37 | self.assertEqual(Run("100<"), [1]) 38 | 39 | def test_parens(self): 40 | self.assertEqual(Run("((1))"), [1]) 41 | self.assertEqual(Run("((1&(1|(!0)))&1)"), [1]) 42 | 43 | def test_nests(self): 44 | self.assertEqual(Run("!(1&1)&(1&0)"), [0]) 45 | 46 | def test_chains(self): 47 | self.assertEqual(Run("1&1&1&1"), [1]) 48 | self.assertEqual(Run("1&1&1&0"), [0]) 49 | 50 | def test_multdigits(self): 51 | self.assertEqual(Run("11&11"), [1, 1]) 52 | self.assertEqual(Run("!((00|10)&10)"), [0, 1]) 53 | 54 | def test_circs(self): 55 | self.assertEqual(Run("circ a()->1\na()"), [1]) 56 | self.assertEqual(Run("circ a(b)->b\na(1)"), [1]) 57 | self.assertEqual(Run("circ a(b)->b\na(0)"), [0]) 58 | self.assertEqual(Run("circ a(b,c)->b&c\na(0, 1)"), [0]) 59 | self.assertEqual(Run("circ asdf(n)->cond n->1/0\nasdf(1)"), [1]) 60 | self.assertEqual(Run("circ asdf(n)->cond n->0/1\nasdf(0)"), [1]) 61 | 62 | def test_vars(self): 63 | self.assertEqual(Run("var foo=1\nfoo"), [1]) 64 | self.assertEqual(Run("var foo=11\nfoo"), [1, 1]) 65 | 66 | def test_conds(self): 67 | self.assertEqual(Run("cond 1->var foo=1/var foo=0\nfoo"), [1]) 68 | self.assertEqual(Run("cond 1&(!1)->var foo=1/var foo=0\nfoo"), [0]) 69 | 70 | 71 | suite = unittest.TestLoader().loadTestsFromTestCase(Test) 72 | 73 | def RunTests(): 74 | unittest.main(defaultTest="suite", argv=[sys.argv[0]]) 75 | 76 | if __name__ == "__main__": 77 | RunTests() 78 | 79 | # TODO: fix ! and + precedence 80 | -------------------------------------------------------------------------------- /logicode.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import operator as op 4 | import argparse 5 | import sys 6 | from random import randint 7 | 8 | sys.setrecursionlimit(15000) 9 | 10 | if not hasattr(__builtins__, "raw_input"): 11 | raw_input = input 12 | if not hasattr(__builtins__, "basestring"): 13 | basestring = str 14 | 15 | regex = re._pattern_type 16 | 17 | rWhitespace = re.compile(r"[ \t]+", re.M) 18 | rCommandSeparator = re.compile(r"[\r\n;]+", re.M) 19 | rBits = re.compile(r"[01]+") 20 | rName = re.compile(r"(?!\b[ab]inp\b|\b__scope__\b)[a-zA-Z0-9_$]+") 21 | rRandom = re.compile(r"\?") 22 | rInput = re.compile(r"\b[ab]inp\b") 23 | rScope = re.compile(r"\b__scope__\b") 24 | rInfix = re.compile(r"[&|]") 25 | rPrefix = re.compile(r"[!~@\*]") 26 | rPostfix = re.compile(r"[<>]") 27 | rOpenParenthesis = re.compile(r"\(") 28 | rCloseParenthesis = re.compile(r"\)") 29 | rOpenBracket = re.compile(r"\[") 30 | rCloseBracket = re.compile(r"\]") 31 | rMultilineCond = re.compile(r"\]/\[") 32 | rCircuit = re.compile(r"\bcirc\b") 33 | rVariable = re.compile(r"\bvar\b") 34 | rCondition = re.compile(r"\bcond\b") 35 | rOut = re.compile(r"\bout\b") 36 | rComment = re.compile(r"#.*") 37 | rLambda = re.compile(r"->") 38 | rOr = re.compile(r"/") 39 | rComma = re.compile(r",") 40 | rEquals = re.compile(r"=") 41 | rPlus = re.compile(r"\+") 42 | 43 | rLinestart = re.compile("^", re.M) 44 | rGetParentFunctionName = re.compile("": 144 | start_index += 1 145 | if head: 146 | return lambda scope: [result[0](scope)[start_index]] 147 | return lambda scope: result[0](scope)[start_index:] 148 | # Function call 149 | name = result[0] 150 | args = result[1] 151 | return lambda scope: name(scope)(list(map(lambda arg: arg(scope), args(scope)))) 152 | if length == 1: 153 | return result[0] 154 | 155 | 156 | def Circuit(result): 157 | name = result[1] 158 | arguments = result[2] 159 | body = result[4] 160 | if isinstance(body, list): 161 | expressions = map(lambda l: l[0], body[0][1]) 162 | body = lambda scope: list(filter(None, map(lambda expression: expression(scope), expressions)))[-1] 163 | return lambda scope: scope.set(name, lambda args: body(Inject(Scope(scope), arguments(scope), args))) 164 | 165 | 166 | def Variable(result): 167 | length = len(result[2]) 168 | name = result[1] 169 | if length: 170 | value = result[2][0][1] 171 | else: 172 | value = lambda n: [0] 173 | return lambda scope: scope.set(name, value(scope)) 174 | 175 | 176 | def Condition(result): 177 | condition = result[1] 178 | body = result[3][0] 179 | if isinstance(body[1], list): 180 | expressions_true = map(lambda l: l[0], body[1]) 181 | expressions_false = map(lambda l: l[0], body[3]) 182 | if_true = lambda scope: ([None] + list(filter(None, map(lambda expression: expression(scope), expressions_true))))[-1] 183 | if_false = lambda scope: ([None] + list(filter(None, map(lambda expression: expression(scope), expressions_false))))[-1] 184 | else: 185 | if_true = body[0] 186 | if_false = body[2] 187 | return lambda scope: if_true(scope) if 1 in condition(scope) else if_false(scope) 188 | 189 | 190 | def Out(result): 191 | return lambda scope: Print(result[1](scope)) 192 | 193 | 194 | def GetInput(scope, inputarg): 195 | if not len(scope["input"]): 196 | if inputarg == "a": 197 | temp = list(x for x in raw_input("Input: ") if ord(x) < 256) 198 | for a in range(len(temp)): 199 | temp[a] = bin(ord(temp[a]))[2:] 200 | while len(temp[a]) < 8: 201 | temp[a] = "0" + temp[a] 202 | temp = "".join(temp) 203 | scope["input"] = [[int(x) for x in temp]] 204 | if inputarg == "b": 205 | scope["input"] = [list(map(int, filter(lambda c: c == "0" or c == "1", raw_input("Input: "))))] 206 | return scope["input"].pop() 207 | 208 | 209 | def Print(result): 210 | if result: 211 | print("".join(list(map(str, result)))) 212 | 213 | 214 | # Scope stuff 215 | 216 | def getParentFunctionName(lambda_function): 217 | return rGetParentFunctionName.match(repr(lambda_function)).group(1) 218 | 219 | 220 | def islambda(v): 221 | LAMBDA = lambda: 0 222 | return isinstance(v, type(LAMBDA)) and v.__name__ == LAMBDA.__name__ 223 | 224 | 225 | class Scope: 226 | def __init__(self, parent={}): 227 | self.parent = parent 228 | self.lookup = {} 229 | 230 | def __contains__(self, key): 231 | return key in self.parent or key in self.lookup 232 | 233 | def __getitem__(self, key): 234 | if key in self.lookup: 235 | return self.lookup[key] 236 | else: 237 | return self.parent[key] 238 | 239 | def __setitem__(self, key, value): 240 | if key in self.lookup: 241 | self.lookup[key] = value 242 | elif key in self.parent: 243 | self.parent[key] = value 244 | else: 245 | self.lookup[key] = value 246 | 247 | def __delitem__(self, key): 248 | if key in self.lookup: 249 | del self.lookup[key] 250 | else: 251 | del self.parent[key] 252 | 253 | def __repr__(self): 254 | string = "{" 255 | for key in self.lookup: 256 | value = self.lookup[key] 257 | string += "%s: %s" % (key, 258 | (getParentFunctionName(value) if islambda(value) else "".join(list(map(str, value))) 259 | if isinstance(value, list) else repr(value))) 260 | string += ", " 261 | string = string[:-2] + "}" 262 | if string == "}": 263 | string = "{}" 264 | return (string + 265 | "\n" + 266 | rLinestart.sub(" ", repr(self.parent))) 267 | 268 | def has(self, key): 269 | return key in self 270 | 271 | def get(self, key): 272 | return self[key] 273 | 274 | def set(self, key, value): 275 | self[key] = value 276 | 277 | def delete(self, key): 278 | del self[key] 279 | 280 | 281 | # Dictionaries: 282 | 283 | # Grammars 284 | grammars = { 285 | "CommandSeparator": [rCommandSeparator], 286 | "Bits": [rBits], 287 | "Name": [rName], 288 | "Random": [rRandom], 289 | "Input": [rInput], 290 | "Scope": [rScope], 291 | "Literal": [["|", "Input", "Scope", "Bits", "Name", "Random"]], 292 | "Arguments": [ 293 | rOpenParenthesis, 294 | ["?", rName, ["*", rComma, rName]], 295 | rCloseParenthesis 296 | ], 297 | "Call Arguments": [ 298 | rOpenParenthesis, 299 | ["?", "TopLevelExpression", ["*", rComma, "TopLevelExpression"]], 300 | rCloseParenthesis 301 | ], 302 | "Term": [ 303 | [ 304 | "|", 305 | ["1", rOpenParenthesis, "TopLevelExpression", rCloseParenthesis], 306 | "Literal" 307 | ] 308 | ], 309 | "Alpha": [ 310 | [ 311 | "|", 312 | ["1", rPrefix, "Term"], 313 | ["1", "Name", "Call Arguments"], 314 | ["1", rOpenParenthesis, "TopLevelExpression", rCloseParenthesis], 315 | "Literal" 316 | ] 317 | ], 318 | "Expression": [ 319 | [ 320 | "|", 321 | ["1", "Alpha", rInfix, "Expression"], 322 | ["1", rPrefix, "Term"], 323 | ["1", "Alpha", ["+", rPostfix]], 324 | ["1", "Name", "Call Arguments"], 325 | ["1", rOpenParenthesis, "TopLevelExpression", rCloseParenthesis], 326 | "Literal" 327 | ] 328 | ], 329 | "TopLevelExpression": [ 330 | [ 331 | "|", 332 | ["1", "Expression", rPlus, "TopLevelExpression"], 333 | ["1", "Expression"] 334 | ] 335 | ], 336 | "Circuit": [ 337 | rCircuit, 338 | rName, 339 | "Arguments", 340 | rLambda, 341 | [ 342 | "|", 343 | "Condition", 344 | "TopLevelExpression", 345 | "Variable", 346 | "Out", 347 | [ 348 | "1", rOpenBracket, 349 | ["+", ["|", "CommandSeparator", "Condition", "Variable", "TopLevelExpression", "Out"]], 350 | rCloseBracket 351 | ] 352 | ] 353 | ], 354 | "Variable": [ 355 | rVariable, rName, 356 | ["?", rEquals, "TopLevelExpression"] 357 | ], 358 | "Condition": [ 359 | rCondition, 360 | "TopLevelExpression", 361 | rLambda, 362 | [ 363 | "|", 364 | [ 365 | "1", 366 | ["|", "Variable", "Out", "TopLevelExpression"], 367 | rOr, 368 | ["|", "Variable", "Out", "TopLevelExpression"] 369 | ], [ 370 | "1", rOpenBracket, 371 | ["+", ["|", "CommandSeparator", "Variable", "Out", "TopLevelExpression"]], 372 | rMultilineCond, 373 | ["+", ["|", "CommandSeparator", "Variable", "Out", "TopLevelExpression"]], 374 | rCloseBracket 375 | ] 376 | ] 377 | ], 378 | "Out": [rOut, "TopLevelExpression"], 379 | "Comment": [rComment], 380 | "Program": [ 381 | [ 382 | "+", 383 | ["|", "CommandSeparator", "Comment", "Circuit", "Variable", "Condition", "Out", "TopLevelExpression"] 384 | ] 385 | ] 386 | } 387 | 388 | # Transforming grammars to functions 389 | transform = { 390 | "CommandSeparator": NoLambda, 391 | "Bits": Bits, 392 | "Name": Name, 393 | "Random": Random, 394 | "Input": Input, 395 | "Scope": ScopeTransform, 396 | "Literal": Literal, 397 | "Arguments": Arguments, 398 | "Call Arguments": Arguments, 399 | "Term": Expression, 400 | "Alpha": Expression, 401 | "Expression": Expression, 402 | "TopLevelExpression": Expression, 403 | "Circuit": Circuit, 404 | "Variable": Variable, 405 | "Condition": Condition, 406 | "Out": Out, 407 | "Comment": NoLambda 408 | } 409 | 410 | # Mins and maxes 411 | mins = { 412 | "?": 0, 413 | "*": 0, 414 | "+": 1 415 | } 416 | 417 | maxes = { 418 | "?": 1, 419 | "*": -1, 420 | "+": -1 421 | } 422 | 423 | 424 | def Inject(scope, keys, values): 425 | for key, value in zip(keys, values): 426 | scope.lookup[key] = value 427 | return scope 428 | 429 | 430 | def Transform(token, argument): 431 | return (transform.get(token, Noop)(argument[0]), argument[1]) 432 | 433 | 434 | def NoTransform(token, argument): 435 | return argument 436 | 437 | 438 | def Get(code, token, process=Transform): 439 | length = 0 440 | match = rWhitespace.match(code) 441 | if match: 442 | string = match.group() 443 | length += len(string) 444 | code = code[length:] 445 | 446 | if isinstance(token, list): 447 | first = token[0] 448 | rest = token[1:] 449 | if first == "|": 450 | for token in rest: 451 | result = Get(code, token, process) 452 | if result[0] != None: 453 | return (result[0], result[1] + length) 454 | return (None, 0) 455 | minN = int(mins.get(first, first)) 456 | maxN = int(maxes.get(first, first)) 457 | result = [] 458 | amount = 0 459 | while amount != maxN: 460 | tokens = [] 461 | success = True 462 | for token in rest: 463 | gotten = Get(code, token, process) 464 | if gotten[0] == None: 465 | success = False 466 | break 467 | tokens += [gotten[0]] 468 | gottenLength = gotten[1] 469 | code = code[gottenLength:] 470 | length += gottenLength 471 | if not success: 472 | break 473 | result += [tokens] 474 | amount += 1 475 | if amount < minN: 476 | return (None, 0) 477 | return (result, length) 478 | 479 | if isinstance(token, basestring): 480 | result = [] 481 | grammar = grammars[token] 482 | for tok in grammar: 483 | gotten = Get(code, tok, process) 484 | if gotten[0] == None: 485 | return (None, 0) 486 | result += [gotten[0]] 487 | gottenLength = gotten[1] 488 | code = code[gottenLength:] 489 | length += gottenLength 490 | return process(token, (result, length)) 491 | 492 | if isinstance(token, regex): 493 | match = token.match(code) 494 | if match: 495 | string = match.group() 496 | return (string, len(string) + length) 497 | return (None, 0) 498 | 499 | 500 | def Run(code="", input="", astify=False, grammar="Program", repl=False, scope=None): 501 | if not scope: 502 | scope = Scope() 503 | if repl: 504 | while repl: 505 | try: 506 | Print(Run(raw_input("Logicode> "), scope=scope)) 507 | except (KeyboardInterrupt, EOFError): 508 | return 509 | scope["input"] = list(map(lambda i: list(map(int, filter(lambda c: c == "0" or c == "1", i))), 510 | filter(None, input.split("\n")[::-1]))) 511 | if astify: 512 | result = Get(code, grammar, NoTransform)[0] 513 | print(Astify(result)) 514 | return 515 | result = Get(code, grammar)[0] 516 | if result: 517 | program = result[0] 518 | for statement in program: 519 | result = statement[0](scope) 520 | return result 521 | 522 | 523 | def Astify(parsed, padding=""): 524 | result = "" 525 | if isinstance(parsed, list): 526 | padding += " " 527 | for part in parsed: 528 | result += Astify(part, padding) 529 | return result 530 | else: 531 | return padding + str(parsed) + "\n" 532 | 533 | 534 | if __name__ == "__main__": 535 | parser = argparse.ArgumentParser(description="Process some integers.") 536 | parser.add_argument("-f", "--file", type=str, nargs="*", default="", help="File path of the program.") 537 | parser.add_argument("-c", "--code", type=str, nargs="?", default="", help="Code of the program.") 538 | parser.add_argument("-i", "--input", type=str, nargs="?", default="", help="Input to the program.") 539 | parser.add_argument("-a", "--astify", action="store_true", help="Print AST instead of interpreting.") 540 | parser.add_argument("-r", "--repl", action="store_true", help="Open as REPL instead of interpreting.") 541 | parser.add_argument("-t", "--test", action="store_true", help="Run unit tests.") 542 | argv = parser.parse_args() 543 | if argv.test: 544 | from test import * 545 | RunTests() 546 | elif argv.repl: 547 | Run(repl=True) 548 | elif len(argv.file): 549 | code = "" 550 | for path in argv.file: 551 | if os.path.isfile(argv.file[0]): 552 | with open(argv.file[0]) as file: 553 | code += file.read() + "\n" 554 | else: 555 | with open(argv.file[0] + ".lgc") as file: 556 | code += file.read() + "\n" 557 | if argv.astify: 558 | Run(code, "", True) 559 | elif argv.input: 560 | Run(code, argv.input) 561 | else: 562 | Run(code) 563 | elif argv.code: 564 | if argv.astify: 565 | Run(argv.code, "", True) 566 | elif argv.input: 567 | Run(argv.code, argv.input) 568 | else: 569 | Run(argv.code) 570 | else: 571 | code = raw_input("Enter program: ") 572 | if argv.astify: 573 | Run(code, "", True) 574 | elif argv.input: 575 | Run(code, argv.input[0]) 576 | else: 577 | Run(code) 578 | --------------------------------------------------------------------------------