aboutsummaryrefslogtreecommitdiffstats
path: root/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/rewriter.cpp
diff options
context:
space:
mode:
authorTaylor Gerring <taylor.gerring@gmail.com>2015-02-16 21:28:33 +0800
committerTaylor Gerring <taylor.gerring@gmail.com>2015-02-16 21:28:33 +0800
commit702218008ee2b6d708d6b2821cdef80736bb3224 (patch)
treed55ff7ce88187082378e7d8e4c2f3aad14d23b4e /Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/rewriter.cpp
parent202362d9258335c695eb75f55f4be74a50a1af33 (diff)
downloadgo-tangerine-702218008ee2b6d708d6b2821cdef80736bb3224.tar.gz
go-tangerine-702218008ee2b6d708d6b2821cdef80736bb3224.tar.zst
go-tangerine-702218008ee2b6d708d6b2821cdef80736bb3224.zip
Add versioned dependencies from godep
Diffstat (limited to 'Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/rewriter.cpp')
-rw-r--r--Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/rewriter.cpp804
1 files changed, 804 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/rewriter.cpp b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/rewriter.cpp
new file mode 100644
index 000000000..4cdce4f0a
--- /dev/null
+++ b/Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/rewriter.cpp
@@ -0,0 +1,804 @@
+#include <stdio.h>
+#include <iostream>
+#include <vector>
+#include <map>
+#include "util.h"
+#include "lllparser.h"
+#include "bignum.h"
+#include "optimize.h"
+#include "rewriteutils.h"
+#include "preprocess.h"
+#include "functions.h"
+#include "opcodes.h"
+
+// Rewrite rules
+std::string macros[][2] = {
+ {
+ "(seq $x)",
+ "$x"
+ },
+ {
+ "(seq (seq) $x)",
+ "$x"
+ },
+ {
+ "(+= $a $b)",
+ "(set $a (+ $a $b))"
+ },
+ {
+ "(*= $a $b)",
+ "(set $a (* $a $b))"
+ },
+ {
+ "(-= $a $b)",
+ "(set $a (- $a $b))"
+ },
+ {
+ "(/= $a $b)",
+ "(set $a (/ $a $b))"
+ },
+ {
+ "(%= $a $b)",
+ "(set $a (% $a $b))"
+ },
+ {
+ "(^= $a $b)",
+ "(set $a (^ $a $b))"
+ },
+ {
+ "(!= $a $b)",
+ "(iszero (eq $a $b))"
+ },
+ {
+ "(assert $x)",
+ "(unless $x (stop))"
+ },
+ {
+ "(min $a $b)",
+ "(with $1 $a (with $2 $b (if (lt $1 $2) $1 $2)))"
+ },
+ {
+ "(max $a $b)",
+ "(with $1 $a (with $2 $b (if (lt $1 $2) $2 $1)))"
+ },
+ {
+ "(smin $a $b)",
+ "(with $1 $a (with $2 $b (if (slt $1 $2) $1 $2)))"
+ },
+ {
+ "(smax $a $b)",
+ "(with $1 $a (with $2 $b (if (slt $1 $2) $2 $1)))"
+ },
+ {
+ "(if $cond $do (else $else))",
+ "(if $cond $do $else)"
+ },
+ {
+ "(code $code)",
+ "$code"
+ },
+ {
+ "(slice $arr $pos)",
+ "(add $arr (mul 32 $pos))",
+ },
+ {
+ "(array $len)",
+ "(alloc (mul 32 $len))"
+ },
+ {
+ "(while $cond $do)",
+ "(until (iszero $cond) $do)",
+ },
+ {
+ "(while (iszero $cond) $do)",
+ "(until $cond $do)",
+ },
+ {
+ "(if $cond $do)",
+ "(unless (iszero $cond) $do)",
+ },
+ {
+ "(if (iszero $cond) $do)",
+ "(unless $cond $do)",
+ },
+ {
+ "(access (. self storage) $ind)",
+ "(sload $ind)"
+ },
+ {
+ "(access $var $ind)",
+ "(mload (add $var (mul 32 $ind)))"
+ },
+ {
+ "(set (access (. self storage) $ind) $val)",
+ "(sstore $ind $val)"
+ },
+ {
+ "(set (access $var $ind) $val)",
+ "(mstore (add $var (mul 32 $ind)) $val)"
+ },
+ {
+ "(getch $var $ind)",
+ "(mod (mload (sub (add $var $ind) 31)) 256)"
+ },
+ {
+ "(setch $var $ind $val)",
+ "(mstore8 (add $var $ind) $val)",
+ },
+ {
+ "(send $to $value)",
+ "(~call (sub (gas) 25) $to $value 0 0 0 0)"
+ },
+ {
+ "(send $gas $to $value)",
+ "(~call $gas $to $value 0 0 0 0)"
+ },
+ {
+ "(sha3 $x)",
+ "(seq (set $1 $x) (~sha3 (ref $1) 32))"
+ },
+ {
+ "(sha3 $mstart (= chars $msize))",
+ "(~sha3 $mstart $msize)"
+ },
+ {
+ "(sha3 $mstart $msize)",
+ "(~sha3 $mstart (mul 32 $msize))"
+ },
+ {
+ "(id $0)",
+ "$0"
+ },
+ {
+ "(return $x)",
+ "(seq (set $1 $x) (~return (ref $1) 32))"
+ },
+ {
+ "(return $mstart (= chars $msize))",
+ "(~return $mstart $msize)"
+ },
+ {
+ "(return $start $len)",
+ "(~return $start (mul 32 $len))"
+ },
+ {
+ "(&& $x $y)",
+ "(if $x $y 0)"
+ },
+ {
+ "(|| $x $y)",
+ "(with $1 $x (if $1 $1 $y))"
+ },
+ {
+ "(>= $x $y)",
+ "(iszero (slt $x $y))"
+ },
+ {
+ "(<= $x $y)",
+ "(iszero (sgt $x $y))"
+ },
+ {
+ "(create $code)",
+ "(create 0 $code)"
+ },
+ {
+ "(create $endowment $code)",
+ "(with $1 (msize) (create $endowment (get $1) (lll (outer $code) (msize))))"
+ },
+ {
+ "(sha256 $x)",
+ "(with $1 (alloc 64) (seq (mstore (add (get $1) 32) $x) (pop (~call 101 2 0 (add (get $1) 32) 32 (get $1) 32)) (mload (get $1))))"
+ },
+ {
+ "(sha256 $arr (= chars $sz))",
+ "(with $1 (alloc 32) (seq (pop (~call 101 2 0 $arr $sz (get $1) 32)) (mload (get $1))))"
+ },
+ {
+ "(sha256 $arr $sz)",
+ "(with $1 (alloc 32) (seq (pop (~call 101 2 0 $arr (mul 32 $sz) (get $1) 32)) (mload (get $1))))"
+ },
+ {
+ "(ripemd160 $x)",
+ "(with $1 (alloc 64) (seq (mstore (add (get $1) 32) $x) (pop (~call 101 3 0 (add (get $1) 32) 32 (get $1) 32)) (mload (get $1))))"
+ },
+ {
+ "(ripemd160 $arr (= chars $sz))",
+ "(with $1 (alloc 32) (seq (pop (~call 101 3 0 $arr $sz (mload $1) 32)) (mload (get $1))))"
+ },
+ {
+ "(ripemd160 $arr $sz)",
+ "(with $1 (alloc 32) (seq (pop (~call 101 3 0 $arr (mul 32 $sz) (get $1) 32)) (mload (get $1))))"
+ },
+ {
+ "(ecrecover $h $v $r $s)",
+ "(with $1 (alloc 160) (seq (mstore (get $1) $h) (mstore (add (get $1) 32) $v) (mstore (add (get $1) 64) $r) (mstore (add (get $1) 96) $s) (pop (~call 101 1 0 (get $1) 128 (add (get $1 128)) 32)) (mload (add (get $1) 128))))"
+ },
+ {
+ "(inset $x)",
+ "$x"
+ },
+ {
+ "(create $x)",
+ "(with $1 (msize) (create $val (get $1) (lll $code (get $1))))"
+ },
+ {
+ "(with (= $var $val) $cond)",
+ "(with $var $val $cond)"
+ },
+ {
+ "(log $t1)",
+ "(~log1 0 0 $t1)"
+ },
+ {
+ "(log $t1 $t2)",
+ "(~log2 0 0 $t1 $t2)"
+ },
+ {
+ "(log $t1 $t2 $t3)",
+ "(~log3 0 0 $t1 $t2 $t3)"
+ },
+ {
+ "(log $t1 $t2 $t3 $t4)",
+ "(~log4 0 0 $t1 $t2 $t3 $t4)"
+ },
+ {
+ "(logarr $a $sz)",
+ "(~log0 $a (mul 32 $sz))"
+ },
+ {
+ "(logarr $a $sz $t1)",
+ "(~log1 $a (mul 32 $sz) $t1)"
+ },
+ {
+ "(logarr $a $sz $t1 $t2)",
+ "(~log2 $a (mul 32 $sz) $t1 $t2)"
+ },
+ {
+ "(logarr $a $sz $t1 $t2 $t3)",
+ "(~log3 $a (mul 32 $sz) $t1 $t2 $t3)"
+ },
+ {
+ "(logarr $a $sz $t1 $t2 $t3 $t4)",
+ "(~log4 $a (mul 32 $sz) $t1 $t2 $t3 $t4)"
+ },
+ {
+ "(save $loc $array (= chars $count))",
+ "(with $location (ref $loc) (with $c $count (with $end (div $c 32) (with $i 0 (seq (while (slt $i $end) (seq (sstore (add $i $location) (access $array $i)) (set $i (add $i 1)))) (sstore (add $i $location) (~and (access $array $i) (sub 0 (exp 256 (sub 32 (mod $c 32)))))))))))"
+ },
+ {
+ "(save $loc $array $count)",
+ "(with $location (ref $loc) (with $end $count (with $i 0 (while (slt $i $end) (seq (sstore (add $i $location) (access $array $i)) (set $i (add $i 1)))))))"
+ },
+ {
+ "(load $loc (= chars $count))",
+ "(with $location (ref $loc) (with $c $count (with $a (alloc $c) (with $i 0 (seq (while (slt $i (div $c 32)) (seq (set (access $a $i) (sload (add $location $i))) (set $i (add $i 1)))) (set (access $a $i) (~and (sload (add $location $i)) (sub 0 (exp 256 (sub 32 (mod $c 32)))))) $a)))))"
+ },
+ {
+ "(load $loc $count)",
+ "(with $location (ref $loc) (with $c $count (with $a (alloc $c) (with $i 0 (seq (while (slt $i $c) (seq (set (access $a $i) (sload (add $location $i))) (set $i (add $i 1)))) $a)))))"
+ },
+ {
+ "(unsafe_mcopy $to $from $sz)",
+ "(with _sz $sz (with _from $from (with _to $to (seq (comment STARTING UNSAFE MCOPY) (with _i 0 (while (lt _i _sz) (seq (mstore (add $to _i) (mload (add _from _i))) (set _i (add _i 32)))))))))"
+ },
+ {
+ "(mcopy $to $from $_sz)",
+ "(with _to $to (with _from $from (with _sz $sz (seq (comment STARTING MCOPY (with _i 0 (seq (while (lt (add _i 31) _sz) (seq (mstore (add _to _i) (mload (add _from _i))) (set _i (add _i 32)))) (with _mask (exp 256 (sub 32 (mod _sz 32))) (mstore (add $to _i) (add (mod (mload (add $to _i)) _mask) (and (mload (add $from _i)) (sub 0 _mask))))))))))))"
+ },
+ { "(. msg sender)", "(caller)" },
+ { "(. msg value)", "(callvalue)" },
+ { "(. tx gasprice)", "(gasprice)" },
+ { "(. tx origin)", "(origin)" },
+ { "(. tx gas)", "(gas)" },
+ { "(. $x balance)", "(balance $x)" },
+ { "self", "(address)" },
+ { "(. block prevhash)", "(prevhash)" },
+ { "(. block coinbase)", "(coinbase)" },
+ { "(. block timestamp)", "(timestamp)" },
+ { "(. block number)", "(number)" },
+ { "(. block difficulty)", "(difficulty)" },
+ { "(. block gaslimit)", "(gaslimit)" },
+ { "stop", "(stop)" },
+ { "---END---", "" } //Keep this line at the end of the list
+};
+
+std::vector<rewriteRule> nodeMacros;
+
+// Token synonyms
+std::string synonyms[][2] = {
+ { "or", "||" },
+ { "and", "&&" },
+ { "|", "~or" },
+ { "&", "~and" },
+ { "elif", "if" },
+ { "!", "iszero" },
+ { "~", "~not" },
+ { "not", "iszero" },
+ { "string", "alloc" },
+ { "+", "add" },
+ { "-", "sub" },
+ { "*", "mul" },
+ { "/", "sdiv" },
+ { "^", "exp" },
+ { "**", "exp" },
+ { "%", "smod" },
+ { "<", "slt" },
+ { ">", "sgt" },
+ { "=", "set" },
+ { "==", "eq" },
+ { ":", "kv" },
+ { "---END---", "" } //Keep this line at the end of the list
+};
+
+// Custom setters (need to be registered separately
+// for use with managed storage)
+std::string setters[][2] = {
+ { "+=", "+" },
+ { "-=", "-" },
+ { "*=", "*" },
+ { "/=", "/" },
+ { "%=", "%" },
+ { "^=", "^" },
+ { "---END---", "" } //Keep this line at the end of the list
+};
+
+// Processes mutable array literals
+Node array_lit_transform(Node node) {
+ std::string prefix = "_temp"+mkUniqueToken() + "_";
+ Metadata m = node.metadata;
+ std::map<std::string, Node> d;
+ std::string o = "(seq (set $arr (alloc "+utd(node.args.size()*32)+"))";
+ for (unsigned i = 0; i < node.args.size(); i++) {
+ o += " (mstore (add (get $arr) "+utd(i * 32)+") $"+utd(i)+")";
+ d[utd(i)] = node.args[i];
+ }
+ o += " (get $arr))";
+ return subst(parseLLL(o), d, prefix, m);
+}
+
+
+Node apply_rules(preprocessResult pr);
+
+// Transform "<variable>.<fun>(args...)" into
+// a call
+Node dotTransform(Node node, preprocessAux aux) {
+ Metadata m = node.metadata;
+ // We're gonna make lots of temporary variables,
+ // so set up a unique flag for them
+ std::string prefix = "_temp"+mkUniqueToken()+"_";
+ // Check that the function name is a token
+ if (node.args[0].args[1].type == ASTNODE)
+ err("Function name must be static", m);
+
+ Node dotOwner = node.args[0].args[0];
+ std::string dotMember = node.args[0].args[1].val;
+ // kwargs = map of special arguments
+ std::map<std::string, Node> kwargs;
+ kwargs["value"] = token("0", m);
+ kwargs["gas"] = subst(parseLLL("(- (gas) 25)"), msn(), prefix, m);
+ // Search for as=? and call=code keywords, and isolate the actual
+ // function arguments
+ std::vector<Node> fnargs;
+ std::string as = "";
+ std::string op = "call";
+ for (unsigned i = 1; i < node.args.size(); i++) {
+ fnargs.push_back(node.args[i]);
+ Node arg = fnargs.back();
+ if (arg.val == "=" || arg.val == "set") {
+ if (arg.args[0].val == "as")
+ as = arg.args[1].val;
+ if (arg.args[0].val == "call" && arg.args[1].val == "code")
+ op = "callcode";
+ if (arg.args[0].val == "gas")
+ kwargs["gas"] = arg.args[1];
+ if (arg.args[0].val == "value")
+ kwargs["value"] = arg.args[1];
+ if (arg.args[0].val == "outsz")
+ kwargs["outsz"] = arg.args[1];
+ }
+ }
+ if (dotOwner.val == "self") {
+ if (as.size()) err("Cannot use \"as\" when calling self!", m);
+ as = dotOwner.val;
+ }
+ // Determine the funId and sig assuming the "as" keyword was used
+ int funId = 0;
+ std::string sig;
+ if (as.size() > 0 && aux.localExterns.count(as)) {
+ if (!aux.localExterns[as].count(dotMember))
+ err("Invalid call: "+printSimple(dotOwner)+"."+dotMember, m);
+ funId = aux.localExterns[as][dotMember];
+ sig = aux.localExternSigs[as][dotMember];
+ }
+ // Determine the funId and sig otherwise
+ else if (!as.size()) {
+ if (!aux.globalExterns.count(dotMember))
+ err("Invalid call: "+printSimple(dotOwner)+"."+dotMember, m);
+ std::string key = unsignedToDecimal(aux.globalExterns[dotMember]);
+ funId = aux.globalExterns[dotMember];
+ sig = aux.globalExternSigs[dotMember];
+ }
+ else err("Invalid call: "+printSimple(dotOwner)+"."+dotMember, m);
+ // Pack arguments
+ kwargs["data"] = packArguments(fnargs, sig, funId, m);
+ kwargs["to"] = dotOwner;
+ Node main;
+ // Pack output
+ if (!kwargs.count("outsz")) {
+ main = parseLLL(
+ "(with _data $data (seq "
+ "(pop (~"+op+" $gas $to $value (access _data 0) (access _data 1) (ref $dataout) 32))"
+ "(get $dataout)))");
+ }
+ else {
+ main = parseLLL(
+ "(with _data $data (with _outsz (mul 32 $outsz) (with _out (alloc _outsz) (seq "
+ "(pop (~"+op+" $gas $to $value (access _data 0) (access _data 1) _out _outsz))"
+ "(get _out)))))");
+ }
+ // Set up main call
+
+ Node o = subst(main, kwargs, prefix, m);
+ return o;
+}
+
+// Transform an access of the form self.bob, self.users[5], etc into
+// a storage access
+//
+// There exist two types of objects: finite objects, and infinite
+// objects. Finite objects are packed optimally tightly into storage
+// accesses; for example:
+//
+// data obj[100](a, b[2][4], c)
+//
+// obj[0].a -> 0
+// obj[0].b[0][0] -> 1
+// obj[0].b[1][3] -> 8
+// obj[45].c -> 459
+//
+// Infinite objects are accessed by sha3([v1, v2, v3 ... ]), where
+// the values are a list of array indices and keyword indices, for
+// example:
+// data obj[](a, b[2][4], c)
+// data obj2[](a, b[][], c)
+//
+// obj[0].a -> sha3([0, 0, 0])
+// obj[5].b[1][3] -> sha3([0, 5, 1, 1, 3])
+// obj[45].c -> sha3([0, 45, 2])
+// obj2[0].a -> sha3([1, 0, 0])
+// obj2[5].b[1][3] -> sha3([1, 5, 1, 1, 3])
+// obj2[45].c -> sha3([1, 45, 2])
+Node storageTransform(Node node, preprocessAux aux,
+ bool mapstyle=false, bool ref=false) {
+ Metadata m = node.metadata;
+ // Get a list of all of the "access parameters" used in order
+ // eg. self.users[5].cow[4][m[2]][woof] ->
+ // [--self, --users, 5, --cow, 4, m[2], woof]
+ std::vector<Node> hlist = listfyStorageAccess(node);
+ // For infinite arrays, the terms array will just provide a list
+ // of indices. For finite arrays, it's a list of index*coefficient
+ std::vector<Node> terms;
+ std::string offset = "0";
+ std::string prefix = "";
+ std::string varPrefix = "_temp"+mkUniqueToken()+"_";
+ int c = 0;
+ std::vector<std::string> coefficients;
+ coefficients.push_back("");
+ for (unsigned i = 1; i < hlist.size(); i++) {
+ // We pre-add the -- flag to parameter-like terms. For example,
+ // self.users[m] -> [--self, --users, m]
+ // self.users.m -> [--self, --users, --m]
+ if (hlist[i].val.substr(0, 2) == "--") {
+ prefix += hlist[i].val.substr(2) + ".";
+ std::string tempPrefix = prefix.substr(0, prefix.size()-1);
+ if (!aux.storageVars.offsets.count(tempPrefix))
+ return node;
+ if (c < (signed)coefficients.size() - 1)
+ err("Too few array index lookups", m);
+ if (c > (signed)coefficients.size() - 1)
+ err("Too many array index lookups", m);
+ coefficients = aux.storageVars.coefficients[tempPrefix];
+ // If the size of an object exceeds 2^176, we make it an infinite
+ // array
+ if (decimalGt(coefficients.back(), tt176) && !mapstyle)
+ return storageTransform(node, aux, true, ref);
+ offset = decimalAdd(offset, aux.storageVars.offsets[tempPrefix]);
+ c = 0;
+ if (mapstyle)
+ terms.push_back(token(unsignedToDecimal(
+ aux.storageVars.indices[tempPrefix])));
+ }
+ else if (mapstyle) {
+ terms.push_back(hlist[i]);
+ c += 1;
+ }
+ else {
+ if (c > (signed)coefficients.size() - 2)
+ err("Too many array index lookups", m);
+ terms.push_back(
+ astnode("mul",
+ hlist[i],
+ token(coefficients[coefficients.size() - 2 - c], m),
+ m));
+
+ c += 1;
+ }
+ }
+ if (aux.storageVars.nonfinal.count(prefix.substr(0, prefix.size()-1)))
+ err("Storage variable access not deep enough", m);
+ if (c < (signed)coefficients.size() - 1) {
+ err("Too few array index lookups", m);
+ }
+ if (c > (signed)coefficients.size() - 1) {
+ err("Too many array index lookups", m);
+ }
+ Node o;
+ if (mapstyle) {
+ std::string t = "_temp_"+mkUniqueToken();
+ std::vector<Node> sub;
+ for (unsigned i = 0; i < terms.size(); i++)
+ sub.push_back(asn("mstore",
+ asn("add",
+ tkn(utd(i * 32), m),
+ asn("get", tkn(t+"pos", m), m),
+ m),
+ terms[i],
+ m));
+ sub.push_back(tkn(t+"pos", m));
+ Node main = asn("with",
+ tkn(t+"pos", m),
+ asn("alloc", tkn(utd(terms.size() * 32), m), m),
+ asn("seq", sub, m),
+ m);
+ Node sz = token(utd(terms.size() * 32), m);
+ o = astnode("~sha3",
+ main,
+ sz,
+ m);
+ }
+ else {
+ // We add up all the index*coefficients
+ Node out = token(offset, node.metadata);
+ for (unsigned i = 0; i < terms.size(); i++) {
+ std::vector<Node> temp;
+ temp.push_back(out);
+ temp.push_back(terms[i]);
+ out = astnode("add", temp, node.metadata);
+ }
+ o = out;
+ }
+ if (ref) return o;
+ else return astnode("sload", o, node.metadata);
+}
+
+
+// Recursively applies rewrite rules
+std::pair<Node, bool> apply_rules_iter(preprocessResult pr) {
+ bool changed = false;
+ Node node = pr.first;
+ // If the rewrite rules have not yet been parsed, parse them
+ if (!nodeMacros.size()) {
+ for (int i = 0; i < 9999; i++) {
+ std::vector<Node> o;
+ if (macros[i][0] == "---END---") break;
+ nodeMacros.push_back(rewriteRule(
+ parseLLL(macros[i][0]),
+ parseLLL(macros[i][1])
+ ));
+ }
+ }
+ // Assignment transformations
+ for (int i = 0; i < 9999; i++) {
+ if (setters[i][0] == "---END---") break;
+ if (node.val == setters[i][0]) {
+ node = astnode("=",
+ node.args[0],
+ astnode(setters[i][1],
+ node.args[0],
+ node.args[1],
+ node.metadata),
+ node.metadata);
+ }
+ }
+ // Do nothing to macros
+ if (node.val == "macro") {
+ return std::pair<Node, bool>(node, changed);
+ }
+ // Ignore comments
+ if (node.val == "comment") {
+ return std::pair<Node, bool>(node, changed);
+ }
+ // Special storage transformation
+ if (isNodeStorageVariable(node)) {
+ node = storageTransform(node, pr.second);
+ changed = true;
+ }
+ if (node.val == "ref" && isNodeStorageVariable(node.args[0])) {
+ node = storageTransform(node.args[0], pr.second, false, true);
+ changed = true;
+ }
+ if (node.val == "=" && isNodeStorageVariable(node.args[0])) {
+ Node t = storageTransform(node.args[0], pr.second);
+ if (t.val == "sload") {
+ std::vector<Node> o;
+ o.push_back(t.args[0]);
+ o.push_back(node.args[1]);
+ node = astnode("sstore", o, node.metadata);
+ }
+ changed = true;
+ }
+ // Main code
+ unsigned pos = 0;
+ std::string prefix = "_temp"+mkUniqueToken()+"_";
+ while(1) {
+ if (synonyms[pos][0] == "---END---") {
+ break;
+ }
+ else if (node.type == ASTNODE && node.val == synonyms[pos][0]) {
+ node.val = synonyms[pos][1];
+ changed = true;
+ }
+ pos++;
+ }
+ for (pos = 0; pos < nodeMacros.size() + pr.second.customMacros.size(); pos++) {
+ rewriteRule macro = pos < nodeMacros.size()
+ ? nodeMacros[pos]
+ : pr.second.customMacros[pos - nodeMacros.size()];
+ matchResult mr = match(macro.pattern, node);
+ if (mr.success) {
+ node = subst(macro.substitution, mr.map, prefix, node.metadata);
+ std::pair<Node, bool> o =
+ apply_rules_iter(preprocessResult(node, pr.second));
+ o.second = true;
+ return o;
+ }
+ }
+ // Special transformations
+ if (node.val == "outer") {
+ node = apply_rules(preprocess(node.args[0]));
+ changed = true;
+ }
+ if (node.val == "array_lit") {
+ node = array_lit_transform(node);
+ changed = true;
+ }
+ if (node.val == "fun" && node.args[0].val == ".") {
+ node = dotTransform(node, pr.second);
+ changed = true;
+ }
+ if (node.type == ASTNODE) {
+ unsigned i = 0;
+ if (node.val == "set" || node.val == "ref"
+ || node.val == "get" || node.val == "with") {
+ if (node.args[0].val.size() > 0 && node.args[0].val[0] != '\''
+ && node.args[0].type == TOKEN && node.args[0].val[0] != '$') {
+ node.args[0].val = "'" + node.args[0].val;
+ changed = true;
+ }
+ i = 1;
+ }
+ else if (node.val == "arglen") {
+ node.val = "get";
+ node.args[0].val = "'_len_" + node.args[0].val;
+ i = 1;
+ changed = true;
+ }
+ for (; i < node.args.size(); i++) {
+ std::pair<Node, bool> r =
+ apply_rules_iter(preprocessResult(node.args[i], pr.second));
+ node.args[i] = r.first;
+ changed = changed || r.second;
+ }
+ }
+ else if (node.type == TOKEN && !isNumberLike(node)) {
+ if (node.val.size() >= 2
+ && node.val[0] == '"'
+ && node.val[node.val.size() - 1] == '"') {
+ std::string bin = node.val.substr(1, node.val.size() - 2);
+ unsigned sz = bin.size();
+ std::vector<Node> o;
+ for (unsigned i = 0; i < sz; i += 32) {
+ std::string t = binToNumeric(bin.substr(i, 32));
+ if ((sz - i) < 32 && (sz - i) > 0) {
+ while ((sz - i) < 32) {
+ t = decimalMul(t, "256");
+ i--;
+ }
+ i = sz;
+ }
+ o.push_back(token(t, node.metadata));
+ }
+ node = astnode("array_lit", o, node.metadata);
+ std::pair<Node, bool> r =
+ apply_rules_iter(preprocessResult(node, pr.second));
+ node = r.first;
+ changed = true;
+ }
+ else if (node.val.size() && node.val[0] != '\'' && node.val[0] != '$') {
+ node.val = "'" + node.val;
+ std::vector<Node> args;
+ args.push_back(node);
+ std::string v = node.val.substr(1);
+ node = astnode("get", args, node.metadata);
+ changed = true;
+ }
+ }
+ return std::pair<Node, bool>(node, changed);
+}
+
+Node apply_rules(preprocessResult pr) {
+ for (unsigned i = 0; i < pr.second.customMacros.size(); i++) {
+ pr.second.customMacros[i].pattern =
+ apply_rules(preprocessResult(pr.second.customMacros[i].pattern, preprocessAux()));
+ }
+ while (1) {
+ //std::cerr << printAST(pr.first) <<
+ // " " << pr.second.customMacros.size() << "\n";
+ std::pair<Node, bool> r = apply_rules_iter(pr);
+ if (!r.second) {
+ return r.first;
+ }
+ pr.first = r.first;
+ }
+}
+
+Node validate(Node inp) {
+ Metadata m = inp.metadata;
+ if (inp.type == ASTNODE) {
+ int i = 0;
+ while(validFunctions[i][0] != "---END---") {
+ if (inp.val == validFunctions[i][0]) {
+ std::string sz = unsignedToDecimal(inp.args.size());
+ if (decimalGt(validFunctions[i][1], sz)) {
+ err("Too few arguments for "+inp.val, inp.metadata);
+ }
+ if (decimalGt(sz, validFunctions[i][2])) {
+ err("Too many arguments for "+inp.val, inp.metadata);
+ }
+ }
+ i++;
+ }
+ }
+ for (unsigned i = 0; i < inp.args.size(); i++) validate(inp.args[i]);
+ return inp;
+}
+
+Node postValidate(Node inp) {
+ // This allows people to use ~x as a way of having functions with the same
+ // name and arity as macros; the idea is that ~x is a "final" form, and
+ // should not be remacroed, but it is converted back at the end
+ if (inp.val.size() > 0 && inp.val[0] == '~') {
+ inp.val = inp.val.substr(1);
+ }
+ if (inp.type == ASTNODE) {
+ if (inp.val == ".")
+ err("Invalid object member (ie. a foo.bar not mapped to anything)",
+ inp.metadata);
+ else if (opcode(inp.val) >= 0) {
+ if ((signed)inp.args.size() < opinputs(inp.val))
+ err("Too few arguments for "+inp.val, inp.metadata);
+ if ((signed)inp.args.size() > opinputs(inp.val))
+ err("Too many arguments for "+inp.val, inp.metadata);
+ }
+ else if (isValidLLLFunc(inp.val, inp.args.size())) {
+ // do nothing
+ }
+ else err ("Invalid argument count or LLL function: "+inp.val, inp.metadata);
+ for (unsigned i = 0; i < inp.args.size(); i++) {
+ inp.args[i] = postValidate(inp.args[i]);
+ }
+ }
+ return inp;
+}
+
+Node rewrite(Node inp) {
+ return postValidate(optimize(apply_rules(preprocess(inp))));
+}
+
+Node rewriteChunk(Node inp) {
+ return postValidate(optimize(apply_rules(
+ preprocessResult(
+ validate(inp), preprocessAux()))));
+}
+
+using namespace std;