From d5ecc44be53d184f6e91fbc691690a01a4078b7a Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 2 Sep 2020 15:31:05 -0400 Subject: [PATCH 01/16] Some typo fixes --- examples/advanced/custom_rules.browse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/advanced/custom_rules.browse b/examples/advanced/custom_rules.browse index 789ca12..70dcbc6 100644 --- a/examples/advanced/custom_rules.browse +++ b/examples/advanced/custom_rules.browse @@ -24,7 +24,7 @@ rule while { # return is unncescessary since the result from the last rule in a RuleSet # is implicitly returned while $cond $body - } else { return null } + } else { return nil } } set i 0 From d0adbbb066604373f313ac1bd5e92daa52ba33e3 Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 8 Sep 2020 23:36:24 -0400 Subject: [PATCH 02/16] Leading comments works --- packages/docs/parsers/browse.js | 119 +++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 2 deletions(-) diff --git a/packages/docs/parsers/browse.js b/packages/docs/parsers/browse.js index 0468bb3..0c23386 100644 --- a/packages/docs/parsers/browse.js +++ b/packages/docs/parsers/browse.js @@ -1,4 +1,23 @@ const parser = require("@browselang/parser"); +const util = require("util"); + +const show = (obj) => + console.log(util.inspect(obj, false, null, true /* enable colors */)); + +const getChildren = (type) => + ({ + Program: ["rules"], + Rule: ["fn", "args"], + RuleSet: ["rules"], + Paren: ["expr"], + UnaryExpr: ["expr"], + BinExpr: ["left", "right"], + RuleExpr: ["expr"], + InitRule: ["module", "name"], + Word: [], + Literal: [], + Ident: [], + }[type]); const parseComments = (ast) => { const commentBlocks = ast.comments.reduce((p, c) => { @@ -15,14 +34,110 @@ const parseComments = (ast) => { return p; }, []); - console.log(commentBlocks); + return commentBlocks; +}; + +const dfsTraverse = (node, fn) => { + fn(node); + const children = getChildren(node.type); + if (children) { + children.forEach((child) => { + if (node[child]) { + if (Array.isArray(node[child])) { + node[child].map((child) => dfsTraverse(child, fn)); + } else { + dfsTraverse(node[child], fn); + } + } else if (node[child] === undefined) { + //TODO: module should not be undefined. Null or empty object is better + if (child !== "module") { + show(node); + throw new Error( + `Node did not have the ${child} child indicated by 'getChildren'` + ); + } + } + }); + } else if (child === undefined) { + show(node); + throw new Error(`Unknown Node type for getChildren ${node.type}`); + } +}; + +const bfsTraverse = (node, fn) => { + const queue = []; + queue.push(node); + while (queue.length) { + const curr = queue.shift(); + fn(curr); + const children = getChildren(curr.type); + + if (children) { + children.forEach((child) => { + if (curr[child]) { + if (Array.isArray(curr[child])) { + queue.push(...curr[child]); + } else { + queue.push(curr[child]); + } + } else if (curr[child] === undefined) { + //TODO: module should not be undefined. Null or empty object is better + if (child !== "module") { + show(curr); + throw new Error( + `Node did not have the child ${child}indicated by 'getChildren'` + ); + } + } + }); + } else if (children === undefined) { + show(curr); + throw new Error(`Unknown Node type for getChildren ${curr.type}`); + } + } +}; + +const assignLeadingComment = (ast, comments) => { + /* + * We're going to walk through the AST and look for leading from the list + */ + + const sortedTree = []; + + let sortedTreeIdx = 0; + + //Bfs walks us through the tree in a sorted manner + bfsTraverse(ast, (node) => sortedTree.push(node)); + + for (i in comments) { + const comment = comments[i]; + const commentEnd = comment.source.endIdx; + while (sortedTreeIdx < sortedTree.length) { + const node = sortedTree[sortedTreeIdx]; + /* console.log(`Comment ${comment.source.startIdx}::${comment.source.endIdx}`); + console.log(`Node ${node.source.startIdx}::${node.source.endIdx}`); + console.log("Should discard?", node.source.startIdx < commentEnd); */ + //If the node starts before the comment ends, we don't want it + if (node.source.startIdx < commentEnd) { + sortedTreeIdx++; + } + //Since everything is sorted, the first node we find is the one the comment belongs to + else { + if (node.comments) node.leadingComments.push(comment); + else node.leadingComments = [comment]; + break; + } + } + } }; module.exports = (code, fileName) => { const rtn = {}; const ast = parser.parse(code); - parseComments(ast); + assignLeadingComment(ast, parseComments(ast)); + + dfsTraverse(ast, (node) => node.leadingComments && console.log(node)); return rtn; }; From 236dd1213f914b3aa2f29093c56f56215521b6b3 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 9 Sep 2020 00:09:47 -0400 Subject: [PATCH 03/16] Basic comments should work in browse now --- packages/docs/parsers/browse.js | 26 +++++++++-- packages/docs/parsers/common.js | 71 ++++++++++++++++++++++++++++++ packages/docs/parsers/js.js | 77 +++------------------------------ 3 files changed, 98 insertions(+), 76 deletions(-) create mode 100644 packages/docs/parsers/common.js diff --git a/packages/docs/parsers/browse.js b/packages/docs/parsers/browse.js index 0c23386..0a8adc6 100644 --- a/packages/docs/parsers/browse.js +++ b/packages/docs/parsers/browse.js @@ -1,5 +1,6 @@ const parser = require("@browselang/parser"); const util = require("util"); +const { pullTags, parseRtn, parseParams } = require("./common"); const show = (obj) => console.log(util.inspect(obj, false, null, true /* enable colors */)); @@ -114,9 +115,6 @@ const assignLeadingComment = (ast, comments) => { const commentEnd = comment.source.endIdx; while (sortedTreeIdx < sortedTree.length) { const node = sortedTree[sortedTreeIdx]; - /* console.log(`Comment ${comment.source.startIdx}::${comment.source.endIdx}`); - console.log(`Node ${node.source.startIdx}::${node.source.endIdx}`); - console.log("Should discard?", node.source.startIdx < commentEnd); */ //If the node starts before the comment ends, we don't want it if (node.source.startIdx < commentEnd) { sortedTreeIdx++; @@ -131,6 +129,19 @@ const assignLeadingComment = (ast, comments) => { } }; +//Trim source for nicer debugging +const trimSource = (ast) => { + dfsTraverse(ast, (node) => { + node.source = { + ...node.source, + sourceString: node.source.sourceString.slice( + node.source.startIdx, + node.source.endIdx + ), + }; + }); +}; + module.exports = (code, fileName) => { const rtn = {}; @@ -138,6 +149,13 @@ module.exports = (code, fileName) => { assignLeadingComment(ast, parseComments(ast)); - dfsTraverse(ast, (node) => node.leadingComments && console.log(node)); + trimSource(ast); + dfsTraverse(ast, (node) => { + if (node.leadingComments) { + node.commentTags = pullTags( + leadingComments.map((comment) => comment.value) + ); + } + }); return rtn; }; diff --git a/packages/docs/parsers/common.js b/packages/docs/parsers/common.js new file mode 100644 index 0000000..612f3e4 --- /dev/null +++ b/packages/docs/parsers/common.js @@ -0,0 +1,71 @@ +const safeMergeObjs = (o1, o2) => { + const rtn = { ...o2 }; + Object.keys(o1).forEach((key) => { + if (rtn[key] !== undefined) { + const throwStr = `Cannot define key ${key} multiple times on the same structure`; + throw new Error(throwStr); + } + rtn[key] = o1[key]; + }); + return rtn; +}; + +const pullTags = (comment) => { + console.log("COMMENT", comment); + const rtn = {}; + const annotationMatch = /(@\w+) {(((?:\\})|[^}])*)}/g; + let matches; + + if (comment.startsWith("*")) { + while ((matches = annotationMatch.exec(comment)) !== null) { + const tag = matches[1]; + + let val = matches[2].replace(/^\s*\*/gm, ""); + val = val.replace(/\\}/g, "}"); + + const [leadingWhitespace] = /^\s*/.exec(val); + val = val.replace( + new RegExp(`^[ \\t]{${leadingWhitespace.length}}`, "gm"), + "" + ); + if (val.endsWith("\n")) val = val.slice(0, -1); + rtn[tag] = val; + } + } + return rtn; +}; + +const pullAllTags = (comments) => + comments.map((comment) => pullTags(comment.value)).reduce(safeMergeObjs, {}); + +const parseParams = (paramString) => { + const rtn = {}; + const paramMatch = /\[(?:(\w*)(?::\s(.+))?)\]\s*([^\[]*)/g; + let matches; + while ((matches = paramMatch.exec(paramString)) !== null) { + const name = matches[1]; + const type = matches[2]; + const description = matches[3]; + rtn[name] = { + type, + description, + }; + } + return rtn; +}; + +const parseRtn = (rtnString) => { + const matches = /(\[(.*)\])?\s*(.+)/g.exec(rtnString); + const type = matches[2] || "any"; + const description = matches[3]; + return { + type: type.trim(), + description: description.trim(), + }; +}; + +module.exports = { + pullTags: pullAllTags, + parseRtn, + parseParams, +}; diff --git a/packages/docs/parsers/js.js b/packages/docs/parsers/js.js index e4d1b0e..040cf03 100644 --- a/packages/docs/parsers/js.js +++ b/packages/docs/parsers/js.js @@ -1,6 +1,7 @@ const traverse = require("@babel/traverse").default; const parser = require("@babel/parser"); const assert = require("assert"); +const { pullTags, parseRtn, parseParams } = require("./common"); const split = (arr, n) => { const rtn = []; @@ -11,18 +12,6 @@ const split = (arr, n) => { return rtn; }; -const safeMergeObjs = (o1, o2) => { - const rtn = { ...o2 }; - Object.keys(o1).forEach((key) => { - if (rtn[key] !== undefined) { - const throwStr = `Cannot define key ${key} multiple times on the same structure`; - throw new Error(throwStr); - } - rtn[key] = o1[key]; - }); - return rtn; -}; - //Removes a bunch of extra stuff from block comments such as the newlines and the *'s const cleanComment = (comment) => comment @@ -32,52 +21,6 @@ const cleanComment = (comment) => .join("") .trim(); -const pullTags = (comment) => { - const rtn = {}; - const annotationMatch = /(@\w+) {(((?:\\})|[^}])*)}/g; - let matches; - - if (comment.startsWith("*")) { - while ((matches = annotationMatch.exec(comment)) !== null) { - const tag = matches[1]; - - let val = matches[2].replace(/^\s*\*/gm, ""); - val = val.replace(/\\}/g, "}"); - - const [leadingWhitespace] = /^\s*/.exec(val); - val = val.replace( - new RegExp(`^[ \\t]{${leadingWhitespace.length}}`, "gm"), - "" - ); - if (val.endsWith("\n")) val = val.slice(0, -1); - rtn[tag] = val; - } - } - return rtn; -}; - -/* - * TODO: Only pull from comments that start with * - */ -const pullAllTags = (comments) => - comments.map((comment) => pullTags(comment.value)).reduce(safeMergeObjs, {}); - -const parseParams = (paramString) => { - const rtn = {}; - const paramMatch = /\[(?:(\w*)(?::\s(.+))?)\]\s*([^\[]*)/g; - let matches; - while ((matches = paramMatch.exec(paramString)) !== null) { - const name = matches[1]; - const type = matches[2]; - const description = matches[3]; - rtn[name] = { - type, - description, - }; - } - return rtn; -}; - const parseConfig = (configString) => { const rtn = {}; split(configString.split(/[\[\]]/).slice(1), 2).map((arr) => { @@ -97,22 +40,12 @@ const parseConfig = (configString) => { return rtn; }; -const parseRtn = (rtnString) => { - const matches = /(\[(.*)\])?\s*(.+)/g.exec(rtnString); - const type = matches[2] || "any"; - const description = matches[3]; - return { - type: type.trim(), - description: description.trim(), - }; -}; - /* * Process a single annotated rule */ const processRule = (rule) => { const rtn = {}; - const tags = pullAllTags(rule.leadingComments); + const tags = pullTags(rule.leadingComments); /* Parse the help tag */ if (tags["@help"] === undefined && tags["@desc"] === undefined) { //If the help and desc tags have no data we grab all of the text @@ -188,7 +121,7 @@ const processRules = (rules) => { commentedRules.forEach((rule) => { const ruleName = rule.key.name || rule.key.value; rtn[ruleName] = {}; - const tags = pullAllTags(rule.leadingComments); + const tags = pullTags(rule.leadingComments); /* Parse the help tag */ if (tags["@help"] === undefined && tags["@desc"] === undefined) { //If the help and desc tags have no data we grab all of the text @@ -247,7 +180,7 @@ const processConfig = (config) => { //TODO: We should try to grab the name, type, and init value const propertyName = property.key.name; - const tags = pullAllTags(property.leadingComments || []); + const tags = pullTags(property.leadingComments || []); if (tags["@config"] === undefined) { rtn[propertyName] = (property.leadingComments || []) @@ -319,7 +252,7 @@ module.exports = (code, fileName) => { */ if (path.node.leadingComments !== undefined) { //Find the scope tag - const tags = pullAllTags(path.node.leadingComments); + const tags = pullTags(path.node.leadingComments); // In the case of just a scope declaration. if (tags["@scope"] && tags["@rule"] === undefined) { From 09144f003995b5525a61bd13857af937d0ffaa4c Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 9 Sep 2020 00:22:55 -0400 Subject: [PATCH 04/16] First tag parsed --- packages/core/stdlib/math/main.browse | 1 + packages/docs/parsers/browse.js | 10 +++++++--- packages/docs/parsers/common.js | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/core/stdlib/math/main.browse b/packages/core/stdlib/math/main.browse index a027536..caccacb 100644 --- a/packages/core/stdlib/math/main.browse +++ b/packages/core/stdlib/math/main.browse @@ -23,6 +23,7 @@ rule toPrecision { # Math.* fns rule abs { bind x; return (native:fn abs $x) } +#* @help { The arc-cos of a number } rule acos { bind x; return (native:fn acos $x) } rule acosh { bind x; return (native:fn acosh $x) } rule asin { bind x; return (native:fn asin $x) } diff --git a/packages/docs/parsers/browse.js b/packages/docs/parsers/browse.js index 0a8adc6..334afd4 100644 --- a/packages/docs/parsers/browse.js +++ b/packages/docs/parsers/browse.js @@ -152,10 +152,14 @@ module.exports = (code, fileName) => { trimSource(ast); dfsTraverse(ast, (node) => { if (node.leadingComments) { - node.commentTags = pullTags( - leadingComments.map((comment) => comment.value) - ); + node.commentTags = pullTags(node.leadingComments); } }); + dfsTraverse( + ast, + (node) => + node.leadingComments && + console.log("Found", node.leadingComments, node.source, node.commentTags) + ); return rtn; }; diff --git a/packages/docs/parsers/common.js b/packages/docs/parsers/common.js index 612f3e4..409e9de 100644 --- a/packages/docs/parsers/common.js +++ b/packages/docs/parsers/common.js @@ -11,7 +11,6 @@ const safeMergeObjs = (o1, o2) => { }; const pullTags = (comment) => { - console.log("COMMENT", comment); const rtn = {}; const annotationMatch = /(@\w+) {(((?:\\})|[^}])*)}/g; let matches; @@ -35,6 +34,7 @@ const pullTags = (comment) => { return rtn; }; +//TODO: Doesn't seem to work if the @tag isn't the first thing in the comment const pullAllTags = (comments) => comments.map((comment) => pullTags(comment.value)).reduce(safeMergeObjs, {}); From 19cded3413e3007de3f78952b598d9bb79876f1a Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 9 Sep 2020 20:42:42 -0400 Subject: [PATCH 05/16] Fixed some bugs --- packages/docs/parsers/browse.js | 51 ++++++++++++++++++++++----- packages/docs/parsers/common.js | 50 +++++++++++++++++++++++++++ packages/docs/parsers/js.js | 61 ++++----------------------------- 3 files changed, 99 insertions(+), 63 deletions(-) diff --git a/packages/docs/parsers/browse.js b/packages/docs/parsers/browse.js index 334afd4..152c5e3 100644 --- a/packages/docs/parsers/browse.js +++ b/packages/docs/parsers/browse.js @@ -1,6 +1,6 @@ const parser = require("@browselang/parser"); const util = require("util"); -const { pullTags, parseRtn, parseParams } = require("./common"); +const { pullTags, parseRtn, parseParams, processRule } = require("./common"); const show = (obj) => console.log(util.inspect(obj, false, null, true /* enable colors */)); @@ -20,6 +20,14 @@ const getChildren = (type) => Ident: [], }[type]); +const cleanComment = (comment) => + comment + .split("\n") + .map((line) => line.split("#")[1]) + .filter(Boolean) + .join("") + .trim(); + const parseComments = (ast) => { const commentBlocks = ast.comments.reduce((p, c) => { if (p.length === 0) return [c]; @@ -150,16 +158,41 @@ module.exports = (code, fileName) => { assignLeadingComment(ast, parseComments(ast)); trimSource(ast); - dfsTraverse(ast, (node) => { - if (node.leadingComments) { - node.commentTags = pullTags(node.leadingComments); + + let scope = null; + + const rules = []; + + bfsTraverse(ast, (node) => { + if (node.leadingComments !== undefined) { + const tags = pullTags(node.leadingComments); + if (tags["@scope"] !== undefined) { + scope = {}; + //If we find the scope tag set the description + scope.desc = tags["@scope"]; + if (tags["@name"] !== undefined) { + //If we find the name, set the name + scope.name = tags["@name"]; + } else { + //Else set the name to be the file name + scope.name = fileName; + } + } + + if (node.type === "Rule") { + rules.push(node); + } } }); - dfsTraverse( - ast, - (node) => - node.leadingComments && - console.log("Found", node.leadingComments, node.source, node.commentTags) + console.log( + rules.map((ruleNode) => + processRule( + ruleNode.leadingComments.map((comment) => ({ + ...comment, + value: cleanComment(comment.value), + })) + ) + ) ); return rtn; }; diff --git a/packages/docs/parsers/common.js b/packages/docs/parsers/common.js index 409e9de..d269662 100644 --- a/packages/docs/parsers/common.js +++ b/packages/docs/parsers/common.js @@ -63,9 +63,59 @@ const parseRtn = (rtnString) => { description: description.trim(), }; }; +/* + * Process a single annotated rule + */ +const processRule = (ruleComments) => { + const rtn = {}; + const tags = pullAllTags(ruleComments); + /* Parse the help tag */ + + console.log("Tags", tags); + if (tags["@help"] === undefined && tags["@desc"] === undefined) { + //If the help and desc tags have no data we grab all of the text + //TODO: Return just the comments not within a tag + rtn.help = ruleComments.map((comment) => comment.value).join("\n"); + } else { + //else we just extract data from @help tags + rtn.help = tags["@help"] || tags["@desc"]; + } + + /* Parse the desc tag */ + if (tags["@desc"] === undefined && tags["@help"] === undefined) { + //If the help and desc tags have no data we grab all of the text + //TODO: Return just the comments not within a tag + rtn.help = ruleComments.map((comment) => comment.value).join("\n"); + } else { + //else we just extract data from @help tags + rtn.help = tags["@desc"] || tags["@help"]; + } + + /* Parse the params tag */ + if (tags["@params"] !== undefined) { + rtn.params = parseParams(tags["@params"]); + } + + /* Parse the returns tag */ + if (tags["@return"] !== undefined) { + rtn.rtn = parseRtn(tags["@return"]); + } + + /* Parse the example tag */ + if (tags["@example"] !== undefined) { + rtn.example = tags["@example"]; + } + + /* Parse the example tag */ + if (tags["@notes"] !== undefined) { + rtn.notes = tags["@notes"]; + } + return rtn; +}; module.exports = { pullTags: pullAllTags, parseRtn, parseParams, + processRule, }; diff --git a/packages/docs/parsers/js.js b/packages/docs/parsers/js.js index 040cf03..49cf3bc 100644 --- a/packages/docs/parsers/js.js +++ b/packages/docs/parsers/js.js @@ -1,7 +1,7 @@ const traverse = require("@babel/traverse").default; const parser = require("@babel/parser"); const assert = require("assert"); -const { pullTags, parseRtn, parseParams } = require("./common"); +const { pullTags, parseRtn, parseParams, processRule } = require("./common"); const split = (arr, n) => { const rtn = []; @@ -40,58 +40,6 @@ const parseConfig = (configString) => { return rtn; }; -/* - * Process a single annotated rule - */ -const processRule = (rule) => { - const rtn = {}; - const tags = pullTags(rule.leadingComments); - /* Parse the help tag */ - if (tags["@help"] === undefined && tags["@desc"] === undefined) { - //If the help and desc tags have no data we grab all of the text - //TODO: Return just the comments not within a tag - rtn.help = rule.leadingComments - .map((node) => cleanComment(node.value)) - .join("\n"); - } else { - //else we just extract data from @help tags - rtn.help = tags["@help"] || tags["@desc"]; - } - - /* Parse the desc tag */ - if (tags["@desc"] === undefined && tags["@help"] === undefined) { - //If the help and desc tags have no data we grab all of the text - //TODO: Return just the comments not within a tag - rtn.help = rule.leadingComments - .map((node) => cleanComment(node.value)) - .join("\n"); - } else { - //else we just extract data from @help tags - rtn.help = tags["@desc"] || tags["@help"]; - } - - /* Parse the params tag */ - if (tags["@params"] !== undefined) { - rtn.params = parseParams(tags["@params"]); - } - - /* Parse the returns tag */ - if (tags["@return"] !== undefined) { - rtn.rtn = parseRtn(tags["@return"]); - } - - /* Parse the example tag */ - if (tags["@example"] !== undefined) { - rtn.example = tags["@example"]; - } - - /* Parse the example tag */ - if (tags["@notes"] !== undefined) { - rtn.notes = tags["@notes"]; - } - return rtn; -}; - /* * Process multiple rules inside an object * @@ -285,7 +233,12 @@ module.exports = (code, fileName) => { //Rules if (!rtn[scopeName]["rules"]) rtn[scopeName]["rules"] = {}; - rtn[scopeName]["rules"][tags["@rule"]] = processRule(path.node); + rtn[scopeName]["rules"][tags["@rule"]] = processRule( + path.node.leadingComments.map((comment) => ({ + ...comment, + value: cleanComment(comment.value), + })) + ); } // In the case of a config definition From 24bf1a7a65db383f14aebdca8330dba46e949d12 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 9 Sep 2020 22:31:56 -0400 Subject: [PATCH 06/16] MVP done modulo some bugs --- packages/docs/parsers/browse.js | 45 ++++++++++++++++++++------------- packages/docs/parsers/common.js | 30 ++++++++++------------ packages/docs/parsers/js.js | 14 +++++----- 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/packages/docs/parsers/browse.js b/packages/docs/parsers/browse.js index 152c5e3..bc4d198 100644 --- a/packages/docs/parsers/browse.js +++ b/packages/docs/parsers/browse.js @@ -21,12 +21,14 @@ const getChildren = (type) => }[type]); const cleanComment = (comment) => - comment - .split("\n") - .map((line) => line.split("#")[1]) - .filter(Boolean) - .join("") - .trim(); + comment.startsWith("*") + ? comment + .split("\n") + .map((line) => line.split("#")[1] || line.split("#")[0]) + .filter(Boolean) + .join("") + .trim() + : ""; const parseComments = (ast) => { const commentBlocks = ast.comments.reduce((p, c) => { @@ -172,7 +174,7 @@ module.exports = (code, fileName) => { scope.desc = tags["@scope"]; if (tags["@name"] !== undefined) { //If we find the name, set the name - scope.name = tags["@name"]; + scope.name = tags["@name"].trim(); } else { //Else set the name to be the file name scope.name = fileName; @@ -184,15 +186,24 @@ module.exports = (code, fileName) => { } } }); - console.log( - rules.map((ruleNode) => - processRule( - ruleNode.leadingComments.map((comment) => ({ - ...comment, - value: cleanComment(comment.value), - })) - ) - ) - ); + + if (scope) { + const scopeName = scope ? scope.name : fileName; + rtn[scopeName] = { + description: scope ? scope.desc : "", + rules: {}, + }; + const processedRules = rules.forEach((ruleNode) => { + rtn[scopeName].rules[ruleNode.args[0].value] = { + ...processRule( + ruleNode.leadingComments.map((comment) => ({ + ...comment, + value: cleanComment(comment.value), + })) + ), + }; + }); + } + console.log(rtn); return rtn; }; diff --git a/packages/docs/parsers/common.js b/packages/docs/parsers/common.js index d269662..adff2b1 100644 --- a/packages/docs/parsers/common.js +++ b/packages/docs/parsers/common.js @@ -15,21 +15,19 @@ const pullTags = (comment) => { const annotationMatch = /(@\w+) {(((?:\\})|[^}])*)}/g; let matches; - if (comment.startsWith("*")) { - while ((matches = annotationMatch.exec(comment)) !== null) { - const tag = matches[1]; + while ((matches = annotationMatch.exec(comment)) !== null) { + const tag = matches[1]; - let val = matches[2].replace(/^\s*\*/gm, ""); - val = val.replace(/\\}/g, "}"); + let val = matches[2].replace(/^\s*\*/gm, ""); + val = val.replace(/\\}/g, "}"); - const [leadingWhitespace] = /^\s*/.exec(val); - val = val.replace( - new RegExp(`^[ \\t]{${leadingWhitespace.length}}`, "gm"), - "" - ); - if (val.endsWith("\n")) val = val.slice(0, -1); - rtn[tag] = val; - } + const [leadingWhitespace] = /^\s*/.exec(val); + val = val.replace( + new RegExp(`^[ \\t]{${leadingWhitespace.length}}`, "gm"), + "" + ); + if (val.endsWith("\n")) val = val.slice(0, -1); + rtn[tag] = val; } return rtn; }; @@ -40,7 +38,7 @@ const pullAllTags = (comments) => const parseParams = (paramString) => { const rtn = {}; - const paramMatch = /\[(?:(\w*)(?::\s(.+))?)\]\s*([^\[]*)/g; + const paramMatch = /\[(?:(\w*)(?::\s(.+))?)\]\s*:?\s*([^\[]*)/g; let matches; while ((matches = paramMatch.exec(paramString)) !== null) { const name = matches[1]; @@ -55,7 +53,7 @@ const parseParams = (paramString) => { }; const parseRtn = (rtnString) => { - const matches = /(\[(.*)\])?\s*(.+)/g.exec(rtnString); + const matches = /(\[(.*)\])?\s*:?\s*(.+)/g.exec(rtnString); const type = matches[2] || "any"; const description = matches[3]; return { @@ -68,10 +66,10 @@ const parseRtn = (rtnString) => { */ const processRule = (ruleComments) => { const rtn = {}; + const tags = pullAllTags(ruleComments); /* Parse the help tag */ - console.log("Tags", tags); if (tags["@help"] === undefined && tags["@desc"] === undefined) { //If the help and desc tags have no data we grab all of the text //TODO: Return just the comments not within a tag diff --git a/packages/docs/parsers/js.js b/packages/docs/parsers/js.js index 49cf3bc..64474a1 100644 --- a/packages/docs/parsers/js.js +++ b/packages/docs/parsers/js.js @@ -14,12 +14,14 @@ const split = (arr, n) => { //Removes a bunch of extra stuff from block comments such as the newlines and the *'s const cleanComment = (comment) => - comment - .split("\n") - .map((line) => line.split("*")[1]) - .filter(Boolean) - .join("") - .trim(); + comment.startsWith("*") + ? comment + .split("\n") + .map((line) => line.split("*")[1]) + .filter(Boolean) + .join("") + .trim() + : ""; const parseConfig = (configString) => { const rtn = {}; From 334832b9bfbd1700c6cdf785ee420be6b85b9caf Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 9 Sep 2020 22:50:52 -0400 Subject: [PATCH 07/16] Fixed a bug --- packages/docs/parsers/browse.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/docs/parsers/browse.js b/packages/docs/parsers/browse.js index bc4d198..db85760 100644 --- a/packages/docs/parsers/browse.js +++ b/packages/docs/parsers/browse.js @@ -28,7 +28,7 @@ const cleanComment = (comment) => .filter(Boolean) .join("") .trim() - : ""; + : null; const parseComments = (ast) => { const commentBlocks = ast.comments.reduce((p, c) => { @@ -194,14 +194,23 @@ module.exports = (code, fileName) => { rules: {}, }; const processedRules = rules.forEach((ruleNode) => { - rtn[scopeName].rules[ruleNode.args[0].value] = { - ...processRule( - ruleNode.leadingComments.map((comment) => ({ - ...comment, - value: cleanComment(comment.value), - })) - ), - }; + //Make sure at least one of the comments starts with a * + ruleNode.leadingComments = ruleNode.leadingComments.filter((comment) => + comment.value.startsWith("*") + ); + if (ruleNode.leadingComments.length) { + rtn[scopeName].rules[ruleNode.args[0].value] = { + ...processRule( + ruleNode.leadingComments.map((comment) => { + const cleanText = cleanComment(comment.value); + return { + ...comment, + value: cleanText, + }; + }) + ), + }; + } }); } console.log(rtn); From 0329a0113eba9b3da312afa7ae700257f8ede7a7 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 10 Sep 2020 00:32:28 -0400 Subject: [PATCH 08/16] Generated math docs --- packages/core/stdlib/math/main.browse | 58 +++++- packages/docs/out/main.md | 279 ++++++++++++++++++++++++++ packages/docs/out/std.md | 36 +--- packages/docs/parsers/browse.js | 47 +++-- packages/docs/plugins/markdownGen.js | 7 +- 5 files changed, 376 insertions(+), 51 deletions(-) create mode 100644 packages/docs/out/main.md diff --git a/packages/core/stdlib/math/main.browse b/packages/core/stdlib/math/main.browse index caccacb..95686bb 100644 --- a/packages/core/stdlib/math/main.browse +++ b/packages/core/stdlib/math/main.browse @@ -1,12 +1,30 @@ import "./native.js" +#* @scope { Standard Math functions } +# @name { Math } + +#*Euler's constant and the base of natural logarithms; approximately 2.718. set E 2.718281828459045 + +#*Natural logarithm of 2; approximately 0.693. set LN10 2.302585092994046 + +#*Natural logarithm of 10; approximately 2.303. set LN2 0.6931471805599453 + +#*Base-2 logarithm of E; approximately 1.443. set LOG10E 0.4342944819032518 + +#*Base-10 logarithm of E; approximately 0.434. set LOG2E 1.4426950408889634 + +#*Ratio of the a circle's circumference to its diameter; approximately 3.14159. set PI 3.141592653589793 + +#*Square root of ½ (or equivalently, 1/√2); approximately 0.707. set SQRT1_2 0.7071067811865476 + +#*Square root of 2; approximately 1.414. set SQRT2 1.4142135623730951 # built in number functions @@ -22,42 +40,76 @@ rule toPrecision { } # Math.* fns +#*Returns the absolute value of x. rule abs { bind x; return (native:fn abs $x) } -#* @help { The arc-cos of a number } +#*Returns the arccosine of x. rule acos { bind x; return (native:fn acos $x) } -rule acosh { bind x; return (native:fn acosh $x) } +#*Returns the hyperbolic arccosine of x. +rule acosh { bind x; bind y; return (native:fn acosh $x) } +#*Returns the arcsine of x. rule asin { bind x; return (native:fn asin $x) } +#*Returns the hyperbolic arcsine of a number. rule asinh { bind x; return (native:fn asinh $x) } +#*Returns the arctangent of x. rule atan { bind x; return (native:fn atan $x) } +#*Returns the hyperbolic arctangent of x. rule atanh { bind x; return (native:fn atanh $x) } +#*Returns the arctangent of the quotient of its arguments. rule atan2 { bind y x; return (native:fn atan2 $y $x) } -rule cbrt { bind x; return (native:fn cbrt $x) } +#*Returns the cube root of x. +rule cbrt { bind x; return (native:fn cbrt $x) }a +#*Returns the smallest integer greater than or equal to x. rule ceil { bind x; return (native:fn ceil $x) } +#*Returns the number of leading zeroes of the 32-bit integer x. rule clz32 { bind x; return (native:fn clz32 $x) } +#*Returns the cosine of x. rule cos { bind x; return (native:fn cos $x) } +#*Returns the hyperbolic cosine of x. rule cosh { bind x; return (native:fn cosh $x) } +#*Returns E^x, where x is the argument, and E is Euler's constant (2.718…, the base of the natural logarithm). rule exp { bind x; return (native:fn exp $x) } +#*Returns subtracting 1 from exp(x). rule expm1 { bind x; return (native:fn expm1 $x) } +#*Returns the largest integer less than or equal to x. rule floor { bind x; return (native:fn floor $x) } +#*Returns the nearest single precision float representation of x. rule fround { bind x; return (native:fn fround $x) } +#*Returns the square root of the sum of squares of both arguments. # TODO: support more than 2 arguments, like in the JS native version rule hypot { bind x y; return (native:fn hypot $x $y) } +#*Returns the result of the 32-bit integer multiplication of x and y. rule imul { bind x y; return (native:fn imul $x $y) } +#*Returns the natural logarithm (㏒e; also, ㏑) of x. rule log { bind x; return (native:fn log $x) } +#*Returns the natural logarithm (㏒e; also ㏑) of 1 + x for the number x. rule log1p { bind x; return (native:fn log1p $x) } +#*Returns the base-10 logarithm of x. rule log10 { bind x; return (native:fn log10 $x) } +#*Returns the base-2 logarithm of x. rule log2 { bind x; return (native:fn log2 $x) } # TODO: support more than 2 arguments, like in the JS native version +#*Returns the largest of x and y numbers. rule max { bind x y; return (native:fn max $x $y) } # TODO: support more than 2 arguments, like in the JS native version +#*Returns the smallest of x and y. rule min { bind x y; return (native:fn min $x $y) } +#*Returns base x to the exponent power y (that is, xy). rule pow { bind x y; return (native:fn pow $x $y) } +#*Returns a pseudo-random number between 0 and 1. rule random { return (native:fn random) } +#*Returns the value of the number x rounded to the nearest integer. rule round { bind x; return (native:fn round $x) } +#*Returns the sign of the x, indicating whether x is positive, negative, or zero. rule sign { bind x; return (native:fn sign $x) } +#*Returns the sine of x. rule sin { bind x; return (native:fn sin $x) } +#*Returns the hyperbolic sine of x. rule sinh { bind x; return (native:fn sinh $x) } +#*Returns the positive square root of x. rule sqrt { bind x; return (native:fn sqrt $x) } +#*Returns the tangent of x. rule tan { bind x; return (native:fn tan $x) } +#*Returns the hyperbolic tangent of x. rule tanh { bind x; return (native:fn tanh $x) } +#*Returns the integer portion of x, removing any fractional digits. rule trunc { bind x; return (native:fn trunc $x) } diff --git a/packages/docs/out/main.md b/packages/docs/out/main.md new file mode 100644 index 0000000..5e0b2b6 --- /dev/null +++ b/packages/docs/out/main.md @@ -0,0 +1,279 @@ +> This was generated using BrowseDoc which is still very much a work in progress + +# Table of Contents + +- [Scope: Math](#scope-Math) + - [`E`](#E) + - [`LN10`](#LN10) + - [`LN2`](#LN2) + - [`LOG10E`](#LOG10E) + - [`LOG2E`](#LOG2E) + - [`PI`](#PI) + - [`SQRT1_2`](#SQRT1_2) + - [`SQRT2`](#SQRT2) + - [`acos x`](#acos-x) + - [`acosh x y`](#acosh-x-y) + - [`asin x`](#asin-x) + - [`asinh x`](#asinh-x) + - [`atan x`](#atan-x) + - [`atanh x`](#atanh-x) + - [`atan2 y x`](#atan2-y-x) + - [`cbrt x`](#cbrt-x) + - [`ceil x`](#ceil-x) + - [`clz32 x`](#clz32-x) + - [`cos x`](#cos-x) + - [`cosh x`](#cosh-x) + - [`exp x`](#exp-x) + - [`expm1 x`](#expm1-x) + - [`floor x`](#floor-x) + - [`fround x`](#fround-x) + - [`hypot x y`](#hypot-x-y) + - [`imul x y`](#imul-x-y) + - [`log x`](#log-x) + - [`log1p x`](#log1p-x) + - [`log10 x`](#log10-x) + - [`log2 x`](#log2-x) + - [`pow x y`](#pow-x-y) + - [`random`](#random) + - [`round x`](#round-x) + - [`sign x`](#sign-x) + - [`sin x`](#sin-x) + - [`sinh x`](#sinh-x) + - [`sqrt x`](#sqrt-x) + - [`tan x`](#tan-x) + - [`tanh x`](#tanh-x) + - [`trunc x`](#trunc-x) + +## Scope `Math` + +Standard Math functions + +### Rules + +### `E` + +@scope { Standard Math functions } @name { Math } +Euler's constant and the base of natural logarithms; approximately 2.718. + +### `LN10` + +Natural logarithm of 2; approximately 0.693. + +### `LN2` + +Natural logarithm of 10; approximately 2.303. + +### `LOG10E` + +Base-2 logarithm of E; approximately 1.443. + +### `LOG2E` + +Base-10 logarithm of E; approximately 0.434. + +### `PI` + +Ratio of the a circle's circumference to its diameter; approximately 3.14159. + +### `SQRT1_2` + +Square root of ½ (or equivalently, 1/√2); approximately 0.707. + +### `SQRT2` + +Square root of 2; approximately 1.414. + +### `acos x` + +- `x` + +Returns the arccosine of x. + +### `acosh x y` + +- `x` +- `y` + +Returns the hyperbolic arccosine of x. + +### `asin x` + +- `x` + +Returns the arcsine of x. + +### `asinh x` + +- `x` + +Returns the hyperbolic arcsine of a number. + +### `atan x` + +- `x` + +Returns the arctangent of x. + +### `atanh x` + +- `x` + +Returns the hyperbolic arctangent of x. + +### `atan2 y x` + +- `y` +- `x` + +Returns the arctangent of the quotient of its arguments. + +### `cbrt x` + +- `x` + +Returns the cube root of x. + +### `ceil x` + +- `x` + +Returns the smallest integer greater than or equal to x. + +### `clz32 x` + +- `x` + +Returns the number of leading zeroes of the 32-bit integer x. + +### `cos x` + +- `x` + +Returns the cosine of x. + +### `cosh x` + +- `x` + +Returns the hyperbolic cosine of x. + +### `exp x` + +- `x` + +Returns E^x, where x is the argument, and E is Euler's constant (2.718…, the base of the natural logarithm). + +### `expm1 x` + +- `x` + +Returns subtracting 1 from exp(x). + +### `floor x` + +- `x` + +Returns the largest integer less than or equal to x. + +### `fround x` + +- `x` + +Returns the nearest single precision float representation of x. + +### `hypot x y` + +- `x` +- `y` + +Returns the square root of the sum of squares of both arguments. TODO: support more than 2 arguments, like in the JS native version + +### `imul x y` + +- `x` +- `y` + +Returns the result of the 32-bit integer multiplication of x and y. + +### `log x` + +- `x` + +Returns the natural logarithm (㏒e; also, ㏑) of x. + +### `log1p x` + +- `x` + +Returns the natural logarithm (㏒e; also ㏑) of 1 + x for the number x. + +### `log10 x` + +- `x` + +Returns the base-10 logarithm of x. + +### `log2 x` + +- `x` + +Returns the base-2 logarithm of x. + +### `pow x y` + +- `x` +- `y` + +Returns base x to the exponent power y (that is, xy). + +### `random` + +Returns a pseudo-random number between 0 and 1. + +### `round x` + +- `x` + +Returns the value of the number x rounded to the nearest integer. + +### `sign x` + +- `x` + +Returns the sign of the x, indicating whether x is positive, negative, or zero. + +### `sin x` + +- `x` + +Returns the sine of x. + +### `sinh x` + +- `x` + +Returns the hyperbolic sine of x. + +### `sqrt x` + +- `x` + +Returns the positive square root of x. + +### `tan x` + +- `x` + +Returns the tangent of x. + +### `tanh x` + +- `x` + +Returns the hyperbolic tangent of x. + +### `trunc x` + +- `x` + +Returns the integer portion of x, removing any fractional digits. diff --git a/packages/docs/out/std.md b/packages/docs/out/std.md index 6680793..669f0ec 100644 --- a/packages/docs/out/std.md +++ b/packages/docs/out/std.md @@ -370,45 +370,17 @@ Get the length of the string or number of elements in an array - Returns: \<**any**\> nil -**Only used within a [rule](#rule-name-body) body** -'bind' lets the rule accept arguments. Strings passed to bind are used to -assign variables that track the incoming values +'bind' lets the rule accept arguments. Strings passed to bind are used to assign variables that track the incoming values ``` -# take 2 arguments and return the sum -rule add { bind x y; return $x + $y } - -# accept options -rule add2 { - bind(print) x y - set z $x + $y - if $print then { print $z } else { return $z } -} - +# take 2 arguments and return the sum rule add { bind x y; return $x + $y } # accept options rule add2 { bind(print) x y set z $x + $y if $print then { print $z } else { return $z } } ``` ### `return value` - `value` \<**T**\> The value to return - - Returns: \<**T**\> The value passed in, unchanged -**Only used within a [rule](#rule-name-body) body** -'return' is often used to make the return value for a rule explicit. It's often -unnecessary however since every rule uses the last evaluated value in its body -as the return value anyway. +'return' is often used to make the return value for a rule explicit. It's often unnecessary however since every rule uses the last evaluated value in its body as the return value anyway. -> The return rule doesn't work like `return` in other languages. `return` is just an -> alias for [id](#id-value) since the last value in a RuleSet is the implicit return value of the -> RuleSet. For example -> -> ``` -> rule f { -> return foo -> return bar -> } -> ``` -> -> In browse, this is valid and the return value is "bar". `return foo` is the same as `id foo` -> Which basically does nothing (a.k.a it's a no-op). and the last rule in the body evaluates to -> "bar" +> The return rule doesn't work like `return` in other languages. `return` is just an alias for [id](#id-value) since the last value in a RuleSet is the implicit return value of the RuleSet. For example `rule f { return foo return bar }` In browse, this is valid and the return value is "bar". `return foo` is the same as `id foo` Which basically does nothing (a.k.a it's a no-op). and the last rule in the body evaluates to "bar" diff --git a/packages/docs/parsers/browse.js b/packages/docs/parsers/browse.js index db85760..04e49c4 100644 --- a/packages/docs/parsers/browse.js +++ b/packages/docs/parsers/browse.js @@ -23,6 +23,7 @@ const getChildren = (type) => const cleanComment = (comment) => comment.startsWith("*") ? comment + .slice(1) .split("\n") .map((line) => line.split("#")[1] || line.split("#")[0]) .filter(Boolean) @@ -131,7 +132,7 @@ const assignLeadingComment = (ast, comments) => { } //Since everything is sorted, the first node we find is the one the comment belongs to else { - if (node.comments) node.leadingComments.push(comment); + if (node.leadingComments) node.leadingComments.push(comment); else node.leadingComments = [comment]; break; } @@ -199,20 +200,42 @@ module.exports = (code, fileName) => { comment.value.startsWith("*") ); if (ruleNode.leadingComments.length) { - rtn[scopeName].rules[ruleNode.args[0].value] = { - ...processRule( - ruleNode.leadingComments.map((comment) => { - const cleanText = cleanComment(comment.value); - return { - ...comment, - value: cleanText, - }; - }) - ), + //First we grab the tags from the comments + const tags = pullTags(ruleNode.leadingComments); + const ruleName = tags["@rule"] || ruleNode.args[0].value; + + const processedRule = processRule( + ruleNode.leadingComments.map((comment) => { + const cleanText = cleanComment(comment.value); + return { + ...comment, + value: cleanText, + }; + }) + ); + + const params = {}; + //If we can't find parameters, we try to autoparse the parameters + tags["@params"] || + (ruleNode.args[1].rules && + [] + .concat( + ...ruleNode.args[1].rules + .filter((rule) => rule.fn.name.name === "bind") + .map((rule) => rule.args.map((arg) => arg.value)) + ) + .forEach((arg) => { + params[arg] = { name: arg }; + })); + + if (Object.keys(params).length) + processedRule["params"] = processedRule["params"] || params; + //In the absenes of an @rule tag, we use the name of the rule below + rtn[scopeName].rules[ruleName] = { + ...processedRule, }; } }); } - console.log(rtn); return rtn; }; diff --git a/packages/docs/plugins/markdownGen.js b/packages/docs/plugins/markdownGen.js index c7a86af..6b4e8f9 100644 --- a/packages/docs/plugins/markdownGen.js +++ b/packages/docs/plugins/markdownGen.js @@ -113,10 +113,9 @@ module.exports = async (docTree, file) => { out.params = bullet( Object.keys(params).map( (param) => - `${shortcode(param)} ${type(params[param].type)} ${subLinks( - params[param].description || "", - ruleMap - )}` + `${shortcode(param)} ${ + params[param].type ? type(params[param].type) : "" + } ${subLinks(params[param].description || "", ruleMap)}` ), 1 ); From bb6ccfe6eac4b2a703f23ee29cdc2dbe7b09db36 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 10 Sep 2020 01:18:59 -0400 Subject: [PATCH 09/16] Completed a TODO that fixed some bugs --- packages/docs/out/main.md | 2 +- packages/docs/parsers/common.js | 28 ++++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/docs/out/main.md b/packages/docs/out/main.md index 5e0b2b6..d61df28 100644 --- a/packages/docs/out/main.md +++ b/packages/docs/out/main.md @@ -52,7 +52,7 @@ Standard Math functions ### `E` -@scope { Standard Math functions } @name { Math } +, , Euler's constant and the base of natural logarithms; approximately 2.718. ### `LN10` diff --git a/packages/docs/parsers/common.js b/packages/docs/parsers/common.js index adff2b1..407c897 100644 --- a/packages/docs/parsers/common.js +++ b/packages/docs/parsers/common.js @@ -61,6 +61,24 @@ const parseRtn = (rtnString) => { description: description.trim(), }; }; + +/* + * Grabs the text that's not part of the autodoc format + */ +const getPlaintext = (comment) => { + const annotationMatch = /(@\w+) {(((?:\\})|[^}])*)}/g; + + let lastMatchedIndex = 0; + const nonMatched = []; + while ((matches = annotationMatch.exec(comment)) !== null) { + nonMatched.push(comment.slice(lastMatchedIndex, matches.index)); + lastMatchedIndex = matches.index + matches[0].length; + } + nonMatched.push(comment.slice(lastMatchedIndex)); + + return nonMatched; +}; + /* * Process a single annotated rule */ @@ -72,8 +90,9 @@ const processRule = (ruleComments) => { if (tags["@help"] === undefined && tags["@desc"] === undefined) { //If the help and desc tags have no data we grab all of the text - //TODO: Return just the comments not within a tag - rtn.help = ruleComments.map((comment) => comment.value).join("\n"); + rtn.help = ruleComments + .map((comment) => getPlaintext(comment.value)) + .join("\n"); } else { //else we just extract data from @help tags rtn.help = tags["@help"] || tags["@desc"]; @@ -82,8 +101,9 @@ const processRule = (ruleComments) => { /* Parse the desc tag */ if (tags["@desc"] === undefined && tags["@help"] === undefined) { //If the help and desc tags have no data we grab all of the text - //TODO: Return just the comments not within a tag - rtn.help = ruleComments.map((comment) => comment.value).join("\n"); + rtn.help = ruleComments + .map((comment) => getPlaintext(comment.value)) + .join("\n"); } else { //else we just extract data from @help tags rtn.help = tags["@desc"] || tags["@help"]; From 9c25ab3ca3890b958eb7a331436e067ecb8c9b61 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 10 Sep 2020 06:24:59 -0400 Subject: [PATCH 10/16] Parameters without type or description are not listed --- packages/core/stdlib/math/main.browse | 2 +- packages/docs/out/main.md | 71 +-------------------------- packages/docs/parsers/browse.js | 2 +- packages/docs/plugins/markdownGen.js | 15 +++--- 4 files changed, 13 insertions(+), 77 deletions(-) diff --git a/packages/core/stdlib/math/main.browse b/packages/core/stdlib/math/main.browse index 95686bb..0181316 100644 --- a/packages/core/stdlib/math/main.browse +++ b/packages/core/stdlib/math/main.browse @@ -45,7 +45,7 @@ rule abs { bind x; return (native:fn abs $x) } #*Returns the arccosine of x. rule acos { bind x; return (native:fn acos $x) } #*Returns the hyperbolic arccosine of x. -rule acosh { bind x; bind y; return (native:fn acosh $x) } +rule acosh { bind x; return (native:fn acosh $x) } #*Returns the arcsine of x. rule asin { bind x; return (native:fn asin $x) } #*Returns the hyperbolic arcsine of a number. diff --git a/packages/docs/out/main.md b/packages/docs/out/main.md index d61df28..d288a3f 100644 --- a/packages/docs/out/main.md +++ b/packages/docs/out/main.md @@ -12,7 +12,7 @@ - [`SQRT1_2`](#SQRT1_2) - [`SQRT2`](#SQRT2) - [`acos x`](#acos-x) - - [`acosh x y`](#acosh-x-y) + - [`acosh x`](#acosh-x) - [`asin x`](#asin-x) - [`asinh x`](#asinh-x) - [`atan x`](#atan-x) @@ -85,145 +85,94 @@ Square root of 2; approximately 1.414. ### `acos x` -- `x` - Returns the arccosine of x. -### `acosh x y` - -- `x` -- `y` +### `acosh x` Returns the hyperbolic arccosine of x. ### `asin x` -- `x` - Returns the arcsine of x. ### `asinh x` -- `x` - Returns the hyperbolic arcsine of a number. ### `atan x` -- `x` - Returns the arctangent of x. ### `atanh x` -- `x` - Returns the hyperbolic arctangent of x. ### `atan2 y x` -- `y` -- `x` - Returns the arctangent of the quotient of its arguments. ### `cbrt x` -- `x` - Returns the cube root of x. ### `ceil x` -- `x` - Returns the smallest integer greater than or equal to x. ### `clz32 x` -- `x` - Returns the number of leading zeroes of the 32-bit integer x. ### `cos x` -- `x` - Returns the cosine of x. ### `cosh x` -- `x` - Returns the hyperbolic cosine of x. ### `exp x` -- `x` - Returns E^x, where x is the argument, and E is Euler's constant (2.718…, the base of the natural logarithm). ### `expm1 x` -- `x` - Returns subtracting 1 from exp(x). ### `floor x` -- `x` - Returns the largest integer less than or equal to x. ### `fround x` -- `x` - Returns the nearest single precision float representation of x. ### `hypot x y` -- `x` -- `y` - Returns the square root of the sum of squares of both arguments. TODO: support more than 2 arguments, like in the JS native version ### `imul x y` -- `x` -- `y` - Returns the result of the 32-bit integer multiplication of x and y. ### `log x` -- `x` - Returns the natural logarithm (㏒e; also, ㏑) of x. ### `log1p x` -- `x` - Returns the natural logarithm (㏒e; also ㏑) of 1 + x for the number x. ### `log10 x` -- `x` - Returns the base-10 logarithm of x. ### `log2 x` -- `x` - Returns the base-2 logarithm of x. ### `pow x y` -- `x` -- `y` - Returns base x to the exponent power y (that is, xy). ### `random` @@ -232,48 +181,32 @@ Returns a pseudo-random number between 0 and 1. ### `round x` -- `x` - Returns the value of the number x rounded to the nearest integer. ### `sign x` -- `x` - Returns the sign of the x, indicating whether x is positive, negative, or zero. ### `sin x` -- `x` - Returns the sine of x. ### `sinh x` -- `x` - Returns the hyperbolic sine of x. ### `sqrt x` -- `x` - Returns the positive square root of x. ### `tan x` -- `x` - Returns the tangent of x. ### `tanh x` -- `x` - Returns the hyperbolic tangent of x. ### `trunc x` -- `x` - Returns the integer portion of x, removing any fractional digits. diff --git a/packages/docs/parsers/browse.js b/packages/docs/parsers/browse.js index 04e49c4..c80ac3f 100644 --- a/packages/docs/parsers/browse.js +++ b/packages/docs/parsers/browse.js @@ -225,7 +225,7 @@ module.exports = (code, fileName) => { .map((rule) => rule.args.map((arg) => arg.value)) ) .forEach((arg) => { - params[arg] = { name: arg }; + params[arg] = {}; })); if (Object.keys(params).length) diff --git a/packages/docs/plugins/markdownGen.js b/packages/docs/plugins/markdownGen.js index 6b4e8f9..5753f36 100644 --- a/packages/docs/plugins/markdownGen.js +++ b/packages/docs/plugins/markdownGen.js @@ -111,12 +111,15 @@ module.exports = async (docTree, file) => { (param) => (out.header += " " + param.trim()) ); out.params = bullet( - Object.keys(params).map( - (param) => - `${shortcode(param)} ${ - params[param].type ? type(params[param].type) : "" - } ${subLinks(params[param].description || "", ruleMap)}` - ), + Object.keys(params) + .map( + (param) => + Object.keys(params[param]).length && + `${shortcode(param)} ${ + params[param].type ? type(params[param].type) : "" + } ${subLinks(params[param].description || "", ruleMap)}` + ) + .filter(Boolean), 1 ); } From 8bba7afc58fe32c67bed417a70ec26c632d7d091 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 10 Sep 2020 06:58:39 -0400 Subject: [PATCH 11/16] Annotated the datetime library and fixed bugs --- packages/docs/index.js | 5 +- packages/docs/out/DateTime.md | 146 ++++++++++ packages/docs/out/{main.md => Math.md} | 41 --- packages/docs/out/rule.md | 386 +++++++++++++++++++++++++ packages/docs/parsers/browse.js | 5 +- 5 files changed, 540 insertions(+), 43 deletions(-) create mode 100644 packages/docs/out/DateTime.md rename packages/docs/out/{main.md => Math.md} (81%) create mode 100644 packages/docs/out/rule.md diff --git a/packages/docs/index.js b/packages/docs/index.js index 7d6eb39..d736f37 100644 --- a/packages/docs/index.js +++ b/packages/docs/index.js @@ -44,6 +44,7 @@ const main = async () => { ), ]; } else if (ext === ".browse") { + console.log(`Parsing ${directory}/${file}`); const stem = path.basename(file, ".browse"); return [ stem, @@ -65,7 +66,9 @@ const main = async () => { const outputs = await Promise.all( pages.map(([stem, doc]) => - markdownPlugin(doc, path.join(outPath, stem + ".md")) + Object.keys(doc).map((scope) => + markdownPlugin(doc, path.join(outPath, scope + ".md")) + ) ) ); diff --git a/packages/docs/out/DateTime.md b/packages/docs/out/DateTime.md new file mode 100644 index 0000000..2b663e9 --- /dev/null +++ b/packages/docs/out/DateTime.md @@ -0,0 +1,146 @@ +> This was generated using BrowseDoc which is still very much a work in progress + +# Table of Contents + +- [Scope: DateTime](#scope-DateTime) + - [`getDay date`](#getDay-date) + - [`getFullYear date`](#getFullYear-date) + - [`getHours date`](#getHours-date) + - [`getMilliseconds date`](#getMilliseconds-date) + - [`getMinutes date`](#getMinutes-date) + - [`getMonth date`](#getMonth-date) + - [`getSeconds date`](#getSeconds-date) + - [`getTime date`](#getTime-date) + - [`getTimezoneOffset date`](#getTimezoneOffset-date) + - [`getUTCDate date`](#getUTCDate-date) + - [`getUTCDay date`](#getUTCDay-date) + - [`getUTCFullYear date`](#getUTCFullYear-date) + - [`getUTCHours date`](#getUTCHours-date) + - [`getUTCMilliseconds date`](#getUTCMilliseconds-date) + - [`getUTCMinutes date`](#getUTCMinutes-date) + - [`getUTCMonth date`](#getUTCMonth-date) + - [`getUTCSeconds date`](#getUTCSeconds-date) + - [`toDateString date`](#toDateString-date) + - [`toISOString date`](#toISOString-date) + - [`toLocaleDateString date tz`](#toLocaleDateString-date-tz) + - [`toLocaleString date tz`](#toLocaleString-date-tz) + - [`toLocaleTimeString date tz`](#toLocaleTimeString-date-tz) + - [`toString date`](#toString-date) + - [`toTimeString date`](#toTimeString-date) + - [`toUTCString date`](#toUTCString-date) + - [`valueOf date`](#valueOf-date) + - [`dayOfYear date`](#dayOfYear-date) + +## Scope `DateTime` + +DateTime utilities + +### Rules + +### `getDay date` + +Returns the day of the week (0–6) for the specified date according to local time. + +### `getFullYear date` + +Returns the day of the week (0–6) for the specified date according to local time. + +### `getHours date` + +Returns the hour (0–23) in the specified date according to local time. + +### `getMilliseconds date` + +Returns the milliseconds (0–999) in the specified date according to local time. + +### `getMinutes date` + +Returns the minutes (0–59) in the specified date according to local time. + +### `getMonth date` + +Returns the month (0–11) in the specified date according to local time. + +### `getSeconds date` + +Returns the seconds (0–59) in the specified date according to local time. + +### `getTime date` + +Returns the numeric value of the specified date as the number of milliseconds since January 1, 1970, 00:00:00 UTC. (Negative values are returned for prior times.) + +### `getTimezoneOffset date` + +Returns the time-zone offset in minutes for the current locale. + +### `getUTCDate date` + +Returns the day (date) of the month (1–31) in the specified date according to universal time. + +### `getUTCDay date` + +Returns the day of the week (0–6) in the specified date according to universal time. + +### `getUTCFullYear date` + +Returns the year (4 digits for 4-digit years) in the specified date according to universal time. + +### `getUTCHours date` + +Returns the hours (0–23) in the specified date according to universal time. + +### `getUTCMilliseconds date` + +Returns the milliseconds (0–999) in the specified date according to universal time. + +### `getUTCMinutes date` + +Returns the minutes (0–59) in the specified date according to universal time. + +### `getUTCMonth date` + +Returns the month (0–11) in the specified date according to universal time. + +### `getUTCSeconds date` + +Returns the seconds (0–59) in the specified date according to universal time. + +### `toDateString date` + +Returns the "date" portion of the Date as a human-readable string like 'Thu Apr 12 2018'. + +### `toISOString date` + +Converts a date to a string following the ISO 8601 Extended Format. + +### `toLocaleDateString date tz` + +Returns a string with a locality sensitive representation of the date portion of this date based on system settings. + +### `toLocaleString date tz` + +Returns a string with a locality-sensitive representation of this date. Overrides the Object.prototype.toLocaleString() method. + +### `toLocaleTimeString date tz` + +Returns a string with a locality-sensitive representation of the time portion of this date, based on system settings. + +### `toString date` + +Returns a string representing the specified Date object. Overrides the Object.prototype.toString() method. + +### `toTimeString date` + +Returns the "time" portion of the Date as a human-readable string. + +### `toUTCString date` + +Converts a date to a string using the UTC timezone. + +### `valueOf date` + +Returns the primitive value of a Date object. Overrides the Object.prototype.valueOf() method. + +### `dayOfYear date` + +Get number of the day in the year @return Number of the day in year diff --git a/packages/docs/out/main.md b/packages/docs/out/Math.md similarity index 81% rename from packages/docs/out/main.md rename to packages/docs/out/Math.md index d288a3f..33136a8 100644 --- a/packages/docs/out/main.md +++ b/packages/docs/out/Math.md @@ -3,14 +3,6 @@ # Table of Contents - [Scope: Math](#scope-Math) - - [`E`](#E) - - [`LN10`](#LN10) - - [`LN2`](#LN2) - - [`LOG10E`](#LOG10E) - - [`LOG2E`](#LOG2E) - - [`PI`](#PI) - - [`SQRT1_2`](#SQRT1_2) - - [`SQRT2`](#SQRT2) - [`acos x`](#acos-x) - [`acosh x`](#acosh-x) - [`asin x`](#asin-x) @@ -50,39 +42,6 @@ Standard Math functions ### Rules -### `E` - -, , -Euler's constant and the base of natural logarithms; approximately 2.718. - -### `LN10` - -Natural logarithm of 2; approximately 0.693. - -### `LN2` - -Natural logarithm of 10; approximately 2.303. - -### `LOG10E` - -Base-2 logarithm of E; approximately 1.443. - -### `LOG2E` - -Base-10 logarithm of E; approximately 0.434. - -### `PI` - -Ratio of the a circle's circumference to its diameter; approximately 3.14159. - -### `SQRT1_2` - -Square root of ½ (or equivalently, 1/√2); approximately 0.707. - -### `SQRT2` - -Square root of 2; approximately 1.414. - ### `acos x` Returns the arccosine of x. diff --git a/packages/docs/out/rule.md b/packages/docs/out/rule.md new file mode 100644 index 0000000..669f0ec --- /dev/null +++ b/packages/docs/out/rule.md @@ -0,0 +1,386 @@ +> This was generated using BrowseDoc which is still very much a work in progress + +# Table of Contents + +- [Scope: std](#scope-std) + - [`help`](#help) + - [`scope`](#scope) + - [`id value`](#id-value) + - [`get key`](#get-key) + - [`arr_get index array`](#arr_get-index-array) + - [`dict_get key dict`](#dict_get-key-dict) + - [`set key value`](#set-key-value) + - [`arr_set index value array`](#arr_set-index-value-array) + - [`dict_set key value dict`](#dict_set-key-value-dict) + - [`unset key`](#unset-key) + - [`dict_unset key dict`](#dict_unset-key-dict) + - [`update key value`](#update-key-value) + - [`push value dest`](#push-value-dest) + - [`pop dest`](#pop-dest) + - [`rule name body`](#rule-name-body) + - [`sleep ms`](#sleep-ms) + - [`print`](#print) + - [`if condition then thenRuleSet else elseRuleSet`](#if-condition-then-thenRuleSet-else-elseRuleSet) + - [`for iterator body`](#for-iterator-body) + - [`eval ruleset inject`](#eval-ruleset-inject) + - [`arr ruleset`](#arr-ruleset) + - [`dict ruleset`](#dict-ruleset) + - [`import`](#import) + - [`string value`](#string-value) + - [`len value`](#len-value) +- [Scope: rule](#scope-rule) + - [`bind`](#bind) + - [`return value`](#return-value) + +## Scope `std` + +This scope is available to every program and consists of all the core rules to write useful browse programs + +### Rules + +### `help` + +Run `help` in a repl, or add it to your code during debugging, to learn about all the rules you can use in a scope + +### `scope` + +Internal: this dumps the current JS scope to stdout for debugging + +### `id value` + +- `value` \<**T**\> Any value + +- Returns: \<**T**\> The value passed in, unchanged + +Returns whatever value is passed in. This is the _identity_ rule + +### `get key` + +- `key` \<**string**\> An identifer + +- Returns: \<**any**\> The value of `key` + +Resolves to the value of the variable `key` + +> The shorthand for this rule is `$`. So, `$someVar` is the +> same as `(get someVar)`. The shorthand syntax is the preferred way to +> read a value. + +### `arr_get index array` + +- `index` \<**number**\> A valid 0-indexed position in the `array` + +- `array` \<**arr\**\> The array to lookup + +- Returns: \<**T**\> The element at `index` in the `array` + +Get the element at `index` in the `array` + +### `dict_get key dict` + +- `key` \<**K**\> A valid key in the dictionary + +- `dict` \<**dict\**\> The dictionary to lookup + +- Returns: \<**V**\> The value of `key` in the `dict` dictionary + +Get the value of `key` in the `dict` dictionary + +### `set key value` + +- `key` \<**string**\> An identifer (a.k.a variable name) + +- `value` \<**T**\> The value to set the variable to + +- Returns: \<**T**\> value + +sets to the value of the variable `key` to `value` + +> 'set' always creates/updates the variable in the immediate/local scope. +> If a variable with the same name exists in a higher scope, it will be +> 'shadowed', not updated. To update a variable instead of creating a +> new one, use the [update](#update-key-value) rule. + +### `arr_set index value array` + +- `index` \<**number**\> A valid 0-indexed position in the `array` + +- `value` \<**T**\> The value to set in the array + +- `array` \<**arr\**\> The array to write to + +- Returns: \<**T**\> The value + +Set the element at `index` in the `array` to `value` + +> To increase the size of the array, see [push](#push-value-dest) or use the `array` library + +### `dict_set key value dict` + +- `key` \<**K**\> The key in the dictionary to set + +- `value` \<**V**\> The value to set `key` to in the dictionary + +- `dict` \<**dict\**\> The dictionary to write to + +- Returns: \<**V**\> The value + +Set the value of `key` in the `dict` dictionary + +### `unset key` + +- `key` \<**string**\> An identifer + +- Returns: \<**any**\> The value stored in the variable key + +Unset the variable 'key' + +### `dict_unset key dict` + +- `key` \<**K**\> A valid key in dict + +- `dict` \<**dict\**\> The dictionary to update + +- Returns: \<**V**\> The value from the deleted pair + +Delete the key-value record matching `key` from the dictionary `dict` + +### `update key value` + +- `key` \<**string**\> An identifer (a.k.a variable name) + +- `value` \<**V**\> The value to set the variable to + +- Returns: \<**V**\> value + +Updates the variable 'key' to the value 'value' + +> 'update' updates the value for the variable `key` in the closest ancestor scope. +> If a variable with the name `key` already exists in the current scope, then +> `update` throws an error. You should use [set](#set-key-value) instead for such cases. + +### `push value dest` + +- `value` \<**T**\> The value to push + +- `dest` \<**arr\**\> The array to push to + +- Returns: \<**number**\> The number of elements in the array after pushing to it + +Push an element to the back of an array + +### `pop dest` + +- `dest` \<**arr\**\> The array to remove an element from + +- Returns: \<**T**\> The value of the element removed + +Remove the element at the back of the array and return it + +### `rule name body` + +- `name` \<**string**\> An identifer to name the rule + +- `body` \<**RuleSet**\> The behavior that should be executed when rule is called with arguments + +- Returns: \<**Rule**\> TODO: This value cannot be used by browse and is only understood by the runtime. Provide a better value + +Define a new rule 'name'. The 'body' has access to two additional rules, [bind](#bind) and [return](#return-value) used to take arguments and return a value + +### `sleep ms` + +- `ms` \<**number**\> The number of milliseconds to sleep for + +- Returns: \<**number**\> ms + +Sleep for 'ms' milliseconds + +> This is a blocking rule + +### `print` + +- Returns: \<**any**\> The value of the last argument passed to print + +Print values to stdout + +``` +# Hello World +print Hello World + +# Since 'print' evaluates to the last argument passed in, it makes +# it easy to compose `print` when debuggin complicated expressions +rule fact { + bind x + if $x <= 1 then { return $x } else { + return (print $x + '! =' $x * (fact $x - 1)) + } +} +fact 4 + +# output = +# 2! = 2 +# 3! = 6 +# 4! = 24 + +``` + +### `if condition then thenRuleSet else elseRuleSet` + +- `condition` \<**any**\> The condition to test + +- `then` \<**"then"**\> The string "then" + +- `thenRuleSet` \<**RuleSet**\> The ruleset that will be executed if condition evaluates to true + ? +- `else` \<**"else"**\> The string "else" + ? +- `elseRuleSet` \<**RuleSet**\> The ruleset that will be executed if condition evaluates to false + +- Returns: \<**any**\> The result of the RuleSet that was evaluated code. `nil` is no `else` claus is provided + +If 'condition' is truthy, evaluate the 'then' RuleSet, else evaluate the 'else' rule set + +> If `else` and `elseRuleSet` are not provided, then nothing is evaluated if the `condition` +> is falsy. The entire `if` rule will evaluate to `nil` in this case + +``` +if ($grade > 60) then { print pass +``` + +### `for iterator body` + +- `iterator` \<**RuleSet**\> The iteration criteria + +- `body` \<**RuleSet**\> The body of the loop + +- Returns: \<**nil**\> nil (TODO: Should return the value of the last evaluated statement, or the number of iterations?) + +Execute the `body` while the `test` expressions in the `interator` do not fail + +> The contents of the iterator is split into multiple parts: +> +> - The very first rule is evaluated once, at the beginning, to setup the loop. +> Usually used to set a iteration variable +> - The remaining rules, except the last rule, are evaulated at the start of each +> rule. A `test` rule is available here that causes the loop to end if the first +> argument passed to `test` is falsy +> - The last rule is run at the end of each loop, i.e. affter the `body` is evaluated, +> but before the `test` rules (previous point) are evaluated again. Usually use to +> increment the iteration variable defined in point 1 + +``` +for { set i 2; test $i < 5; set i $i + 1 } { print loop $i } +``` + +### `eval ruleset inject` + +- `ruleset` \<**RuleSet**\> The RuleSet to evaluate + ? +- `inject` \<**RuleSet**\> A RuleSet that is evaluated in the scope before the ruleset is evaluated + +- Returns: \<**any**\> The result of evaluating the ruleset + +Evaluate a RuleSet. Optionally, inject variables and additional rules into the evaluation context/scope + +> inject is used to add additional variables and rules that can be used by the Ruleset +> This is the "explicit" form of scope injection that's used to make a pleasant experience +> for someone using a given library. See `examples/advanced/custom_rules.browse` in the browse +> repo to see some good examples for this + +``` +# See https://github.com/windsorio/browse/blob/master/examples/advanced/custom_rules.browse + +``` + +### `arr ruleset` + +- `ruleset` \<**RuleSet**\> The RuleSet used to instantiate the array + +- Returns: \<**arr\**\> The array + +Create an Array from a RuleSet + +> `arr` creates a new array, and then evaluates the RuleSet +> A rule called `el` is available inside this RuleSet. It takes one argument +> Each `el` call adds that element to the array before returning the final +> array. +> +> `e` and `_` are aliases for `el` + +``` +set a1 (arr { _ 1; _ 2; _ 3 }) + +# nested arrays +set a2 (arr { + _ (arr { + _ 1 + }) +}) + +``` + +### `dict ruleset` + +- `ruleset` \<**RuleSet**\> The RuleSet used to instantiate the dictionary + +- Returns: \<**dict\**\> The dictionary + +Create a Dictionary from a RuleSet + +> `dict` creates a new dictionary, and then evaluates the RuleSet +> A rule called `record` is available inside this RuleSet. It takes two arguments, +> a `key` and `value`. Each `record` call adds a new record to the dictionary +> mapping the `key` to the `value`. The final dictionary is `returned`. +> +> `r` and `_` are aliases for `record` + +``` +set o1 (dict { _ k1 v1; _ k2 v2 }) + +# nested dictionaries +set o2 (dict { + _ k1 (dict { + _ k2 v2 + }) +}) + +``` + +### `import` + +Import a module. Read the [Browse Modules](#) guide for more info (TODO) + +### `string value` + +- `value` \<**any**\> Any value + +Serialize any value as a string + +### `len value` + +- `value` \<**string | array\**\> A string or array + +Get the length of the string or number of elements in an array + +## Scope `rule` + +### Rules + +### `bind` + +- Returns: \<**any**\> nil + +'bind' lets the rule accept arguments. Strings passed to bind are used to assign variables that track the incoming values + +``` +# take 2 arguments and return the sum rule add { bind x y; return $x + $y } # accept options rule add2 { bind(print) x y set z $x + $y if $print then { print $z } else { return $z } } +``` + +### `return value` + +- `value` \<**T**\> The value to return +- Returns: \<**T**\> The value passed in, unchanged + +'return' is often used to make the return value for a rule explicit. It's often unnecessary however since every rule uses the last evaluated value in its body as the return value anyway. + +> The return rule doesn't work like `return` in other languages. `return` is just an alias for [id](#id-value) since the last value in a RuleSet is the implicit return value of the RuleSet. For example `rule f { return foo return bar }` In browse, this is valid and the return value is "bar". `return foo` is the same as `id foo` Which basically does nothing (a.k.a it's a no-op). and the last rule in the body evaluates to "bar" diff --git a/packages/docs/parsers/browse.js b/packages/docs/parsers/browse.js index c80ac3f..925ae07 100644 --- a/packages/docs/parsers/browse.js +++ b/packages/docs/parsers/browse.js @@ -182,9 +182,12 @@ module.exports = (code, fileName) => { } } - if (node.type === "Rule") { + //All of the rule declarations + if (node.type === "Rule" && node.fn.name.name === "rule") { rules.push(node); } + + //All of the variable declarations } }); From 9a26f33ad384ae8e5f103fb683af76f346f95454 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 10 Sep 2020 08:13:59 -0400 Subject: [PATCH 12/16] Added in variable parsing --- packages/core/stdlib/datetime/main.browse | 55 ++++++++++++++++++++--- packages/docs/out/DateTime.md | 46 +++++++++++++++++-- packages/docs/out/Math.md | 37 ++++++++++++++- packages/docs/out/rule.md | 4 +- packages/docs/out/std.md | 4 +- packages/docs/parsers/browse.js | 38 +++++++++++++++- packages/docs/parsers/common.js | 47 +++++++++++++++++++ packages/docs/plugins/markdownGen.js | 16 +++++-- 8 files changed, 227 insertions(+), 20 deletions(-) diff --git a/packages/core/stdlib/datetime/main.browse b/packages/core/stdlib/datetime/main.browse index bc72e51..84f73fe 100644 --- a/packages/core/stdlib/datetime/main.browse +++ b/packages/core/stdlib/datetime/main.browse @@ -1,14 +1,29 @@ +#* @name { DateTime } +# @scope { DateTime utilities } import math import "./native.js" -set SECOND 1000 -set MINUTE $SECOND * 60 -set HOUR $MINUTE * 60 -set DAY $HOUR * 24 -set WEEK $DAY * 7 +#*Number of seconds in a minute +set SECONDS_PER_MINUTE 60 +#*Number of minutes in an hour +set MINUTES_PER_HOUR 60 +#*Number of hours in a day +set HOURS_PER_DAY 24 +#*Number of days in a week set DAYS_PER_WEEK 7 +#*Number of milliseconds in a second +set SECOND 1000 +#*Number of milliseconds in a minute +set MINUTE $SECOND * $SECONDS_PER_MINUTE +#*Number of milliseconds in an hour +set HOUR $MINUTE * $MINUTES_PER_HOUR +#*Number of milliseconds in a day +set DAY $HOUR * $HOURS_PER_DAY +#*Number of milliseconds in a week +set WEEK $DAY * $DAYS_PER_WEEK + # A date looks like this: # dict { _ __type__ 'Date' ; _ value number } # `value` is in epoch ms @@ -21,50 +36,78 @@ rule Date { bind a b c d e f g; return (native:Date $a $b $c $d $e $f $g) } #################################### ### The Native JS Date functions ### #################################### +#*Returns the day of the month (1–31) for the specified date according to local time. rule getDate { bind date; return (native:date_fn $date getDate) } +#*Returns the day of the week (0–6) for the specified date according to local time. rule getDay { bind date; return (native:date_fn $date getDay) } +#*Returns the day of the week (0–6) for the specified date according to local time. rule getFullYear { bind date; return (native:date_fn $date getFullYear) } +#*Returns the hour (0–23) in the specified date according to local time. rule getHours { bind date; return (native:date_fn $date getHours) } +#*Returns the milliseconds (0–999) in the specified date according to local time. rule getMilliseconds { bind date; return (native:date_fn $date getMilliseconds) } +#*Returns the minutes (0–59) in the specified date according to local time. rule getMinutes { bind date; return (native:date_fn $date getMinutes) } +#*Returns the month (0–11) in the specified date according to local time. rule getMonth { bind date; return (native:date_fn $date getMonth) } +#*Returns the seconds (0–59) in the specified date according to local time. rule getSeconds { bind date; return (native:date_fn $date getSeconds) } +#*Returns the numeric value of the specified date as the number of milliseconds since January 1, 1970, 00:00:00 UTC. (Negative values are returned for prior times.) rule getTime { bind date; return (native:date_fn $date getTime) } +#*Returns the time-zone offset in minutes for the current locale. rule getTimezoneOffset { bind date; return (native:date_fn $date getTimezoneOffset) } +#*Returns the day (date) of the month (1–31) in the specified date according to universal time. rule getUTCDate { bind date; return (native:date_fn $date getUTCDate) } +#*Returns the day of the week (0–6) in the specified date according to universal time. rule getUTCDay { bind date; return (native:date_fn $date getUTCDay) } +#*Returns the year (4 digits for 4-digit years) in the specified date according to universal time. rule getUTCFullYear { bind date; return (native:date_fn $date getUTCFullYear) } +#*Returns the hours (0–23) in the specified date according to universal time. +rule getUTCHours { bind date; return (native:date_fn $date getUTCHours) } +#*Returns the milliseconds (0–999) in the specified date according to universal time. rule getUTCMilliseconds { bind date; return (native:date_fn $date getUTCMilliseconds) } +#*Returns the minutes (0–59) in the specified date according to universal time. rule getUTCMinutes { bind date; return (native:date_fn $date getUTCMinutes) } +#*Returns the month (0–11) in the specified date according to universal time. rule getUTCMonth { bind date; return (native:date_fn $date getUTCMonth) } +#*Returns the seconds (0–59) in the specified date according to universal time. rule getUTCSeconds { bind date; return (native:date_fn $date getUTCSeconds) } +#*Returns the "date" portion of the Date as a human-readable string like 'Thu Apr 12 2018'. rule toDateString { bind date; return (native:date_fn $date toDateString) } +#*Converts a date to a string following the ISO 8601 Extended Format. rule toISOString { bind date; return (native:date_fn $date toISOString) } +#*Returns a string with a locality sensitive representation of the date portion of this date based on system settings. rule toLocaleDateString { bind date tz; return (native:date_fn $date toLocaleDateString $tz) } +#*Returns a string with a locality-sensitive representation of this date rule toLocaleString { bind date tz; return (native:date_fn $date toLocaleString $tz) } +#*Returns a string with a locality-sensitive representation of the time portion of this date, based on system settings. rule toLocaleTimeString { bind date tz; return (native:date_fn $date toLocaleTimeString $tz) } +#*Returns a string representing the specified Date object rule toString { bind date; return (native:date_fn $date toString) } +#*Returns the "time" portion of the Date as a human-readable string. rule toTimeString { bind date; return (native:date_fn $date toTimeString) } +#*Converts a date to a string using the UTC timezone. rule toUTCString { bind date; return (native:date_fn $date toUTCString) } +#*Returns the primitive value of a Date object rule valueOf { bind date; return (native:date_fn $date valueOf) } ##################################### ### Porting the golib/deno stdlib ### ##################################### -# Get number of the day in the year +#* Get number of the day in the year # @return Number of the day in year rule dayOfYear { bind date diff --git a/packages/docs/out/DateTime.md b/packages/docs/out/DateTime.md index 2b663e9..dc4d0df 100644 --- a/packages/docs/out/DateTime.md +++ b/packages/docs/out/DateTime.md @@ -35,7 +35,7 @@ DateTime utilities -### Rules +## Rules ### `getDay date` @@ -119,7 +119,7 @@ Returns a string with a locality sensitive representation of the date portion of ### `toLocaleString date tz` -Returns a string with a locality-sensitive representation of this date. Overrides the Object.prototype.toLocaleString() method. +Returns a string with a locality-sensitive representation of this date ### `toLocaleTimeString date tz` @@ -127,7 +127,7 @@ Returns a string with a locality-sensitive representation of the time portion of ### `toString date` -Returns a string representing the specified Date object. Overrides the Object.prototype.toString() method. +Returns a string representing the specified Date object ### `toTimeString date` @@ -139,8 +139,46 @@ Converts a date to a string using the UTC timezone. ### `valueOf date` -Returns the primitive value of a Date object. Overrides the Object.prototype.valueOf() method. +Returns the primitive value of a Date object ### `dayOfYear date` Get number of the day in the year @return Number of the day in year + +## Variables + +### `SECONDS_PER_MINUTE` + +Number of seconds in a minute + +### `MINUTES_PER_HOUR` + +Number of minutes in an hour + +### `HOURS_PER_DAY` + +Number of hours in a day + +### `DAYS_PER_WEEK` + +Number of days in a week + +### `SECOND` + +Number of milliseconds in a second + +### `MINUTE` + +Number of milliseconds in a minute + +### `HOUR` + +Number of milliseconds in an hour + +### `DAY` + +Number of milliseconds in a day + +### `WEEK` + +Number of milliseconds in a week diff --git a/packages/docs/out/Math.md b/packages/docs/out/Math.md index 33136a8..a33f865 100644 --- a/packages/docs/out/Math.md +++ b/packages/docs/out/Math.md @@ -40,7 +40,7 @@ Standard Math functions -### Rules +## Rules ### `acos x` @@ -169,3 +169,38 @@ Returns the hyperbolic tangent of x. ### `trunc x` Returns the integer portion of x, removing any fractional digits. + +## Variables + +### `Math` + +, , +Euler's constant and the base of natural logarithms; approximately 2.718. + +### `LN10` + +Natural logarithm of 2; approximately 0.693. + +### `LN2` + +Natural logarithm of 10; approximately 2.303. + +### `LOG10E` + +Base-2 logarithm of E; approximately 1.443. + +### `LOG2E` + +Base-10 logarithm of E; approximately 0.434. + +### `PI` + +Ratio of the a circle's circumference to its diameter; approximately 3.14159. + +### `SQRT1_2` + +Square root of ½ (or equivalently, 1/√2); approximately 0.707. + +### `SQRT2` + +Square root of 2; approximately 1.414. diff --git a/packages/docs/out/rule.md b/packages/docs/out/rule.md index 669f0ec..1cff588 100644 --- a/packages/docs/out/rule.md +++ b/packages/docs/out/rule.md @@ -36,7 +36,7 @@ This scope is available to every program and consists of all the core rules to write useful browse programs -### Rules +## Rules ### `help` @@ -364,7 +364,7 @@ Get the length of the string or number of elements in an array ## Scope `rule` -### Rules +## Rules ### `bind` diff --git a/packages/docs/out/std.md b/packages/docs/out/std.md index 669f0ec..1cff588 100644 --- a/packages/docs/out/std.md +++ b/packages/docs/out/std.md @@ -36,7 +36,7 @@ This scope is available to every program and consists of all the core rules to write useful browse programs -### Rules +## Rules ### `help` @@ -364,7 +364,7 @@ Get the length of the string or number of elements in an array ## Scope `rule` -### Rules +## Rules ### `bind` diff --git a/packages/docs/parsers/browse.js b/packages/docs/parsers/browse.js index 925ae07..d76cc4f 100644 --- a/packages/docs/parsers/browse.js +++ b/packages/docs/parsers/browse.js @@ -1,6 +1,12 @@ const parser = require("@browselang/parser"); const util = require("util"); -const { pullTags, parseRtn, parseParams, processRule } = require("./common"); +const { + pullTags, + parseRtn, + parseParams, + processVar, + processRule, +} = require("./common"); const show = (obj) => console.log(util.inspect(obj, false, null, true /* enable colors */)); @@ -165,6 +171,7 @@ module.exports = (code, fileName) => { let scope = null; const rules = []; + const vars = []; bfsTraverse(ast, (node) => { if (node.leadingComments !== undefined) { @@ -187,6 +194,10 @@ module.exports = (code, fileName) => { rules.push(node); } + if (node.type === "Rule" && node.fn.name.name === "set") { + vars.push(node); + } + //All of the variable declarations } }); @@ -196,7 +207,30 @@ module.exports = (code, fileName) => { rtn[scopeName] = { description: scope ? scope.desc : "", rules: {}, + vars: {}, }; + + const processedVars = vars.forEach((varNode) => { + varNode.leadingComments = varNode.leadingComments.filter((comment) => + comment.value.startsWith("*") + ); + if (varNode.leadingComments.length) { + //Grab the tags + const tags = pullTags(varNode.leadingComments); + const varName = tags["@name"] || varNode.args[0].value; + + const processedVar = processVar( + varNode.leadingComments.map((comment) => ({ + ...comment, + value: cleanComment(comment.value), + })) + ); + rtn[scopeName].vars[varName] = { + ...processedVar, + }; + } + }); + const processedRules = rules.forEach((ruleNode) => { //Make sure at least one of the comments starts with a * ruleNode.leadingComments = ruleNode.leadingComments.filter((comment) => @@ -218,7 +252,7 @@ module.exports = (code, fileName) => { ); const params = {}; - //If we can't find parameters, we try to autoparse the parameters + //If we can't find a parameters tag, we try to autoparse the parameters tags["@params"] || (ruleNode.args[1].rules && [] diff --git a/packages/docs/parsers/common.js b/packages/docs/parsers/common.js index 407c897..5259af6 100644 --- a/packages/docs/parsers/common.js +++ b/packages/docs/parsers/common.js @@ -79,6 +79,52 @@ const getPlaintext = (comment) => { return nonMatched; }; +/* + * Process a single annotated variable + */ +const processVar = (variableComments) => { + const rtn = {}; + + const tags = pullAllTags(variableComments); + /* Parse the help tag */ + + if (tags["@help"] === undefined && tags["@desc"] === undefined) { + //If the help and desc tags have no data we grab all of the text + rtn.help = variableComments + .map((comment) => getPlaintext(comment.value)) + .join("\n"); + } else { + //else we just extract data from @help tags + rtn.help = tags["@help"] || tags["@desc"]; + } + + /* Parse the desc tag */ + if (tags["@desc"] === undefined && tags["@help"] === undefined) { + //If the help and desc tags have no data we grab all of the text + rtn.help = variableComments + .map((comment) => getPlaintext(comment.value)) + .join("\n"); + } else { + //else we just extract data from @help tags + rtn.help = tags["@desc"] || tags["@help"]; + } + + if (tags["@type"] !== undefined) { + rtn.type = tags["@type"]; + } + + /* Parse the example tag */ + if (tags["@example"] !== undefined) { + rtn.example = tags["@example"]; + } + + /* Parse the example tag */ + if (tags["@notes"] !== undefined) { + rtn.notes = tags["@notes"]; + } + return rtn; +}; + /* * Process a single annotated rule */ @@ -136,4 +182,5 @@ module.exports = { parseRtn, parseParams, processRule, + processVar, }; diff --git a/packages/docs/plugins/markdownGen.js b/packages/docs/plugins/markdownGen.js index 5753f36..d5e8155 100644 --- a/packages/docs/plugins/markdownGen.js +++ b/packages/docs/plugins/markdownGen.js @@ -81,9 +81,9 @@ module.exports = async (docTree, file) => { readmeLines.push(subLinks(docTree[scope].description || "", ruleMap)); readmeLines.push(line); - const { rules, config } = docTree[scope]; + const { vars, rules, config } = docTree[scope]; if (rules && Object.keys(rules).length) { - readmeLines.push(h3("Rules")); + readmeLines.push(h2("Rules")); const ruleLines = Object.keys(rules).map((rule) => { const { help, desc, params, rtn, example, notes } = rules[rule]; @@ -131,7 +131,7 @@ module.exports = async (docTree, file) => { readmeLines.push(...ruleLines); } if (config && Object.keys(config).length) { - readmeLines.push(h3("Config")); + readmeLines.push(h2("Config")); const configLines = Object.keys(config).map((configVar) => { return `${h4(configVar)}\n( ${italics(config[configVar].type)} ) ${ config[configVar].description @@ -139,6 +139,16 @@ module.exports = async (docTree, file) => { }); readmeLines.push(bullet(configLines)); } + if (vars && Object.keys(vars).length) { + readmeLines.push(h2("Variables")); + const varLines = Object.keys(vars).map((variable) => { + const { help, desc, type } = vars[variable]; + return `${h3(shortcode(variable))}${type ? "\n" + italics(type) : ""}${ + desc ? "\n" + desc : help ? "\n" + help : "" + }`; + }); + readmeLines.push(...varLines); + } }); if (typeof file === "string") { From 71289d425734e8428ce66600b88615cff921a758 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 10 Sep 2020 08:24:03 -0400 Subject: [PATCH 13/16] Add variables to the directory --- packages/core/stdlib/math/main.browse | 4 +- packages/docs/out/DateTime.md | 85 +++++++++++++++------------ packages/docs/out/Math.md | 77 +++++++++++++----------- packages/docs/plugins/markdownGen.js | 28 +++++---- 4 files changed, 107 insertions(+), 87 deletions(-) diff --git a/packages/core/stdlib/math/main.browse b/packages/core/stdlib/math/main.browse index 0181316..372028e 100644 --- a/packages/core/stdlib/math/main.browse +++ b/packages/core/stdlib/math/main.browse @@ -1,7 +1,7 @@ -import "./native.js" - #* @scope { Standard Math functions } # @name { Math } +# TODO: This is a bit hacky. If the @name is called below the import it will be attributed to E rather than to the scope. +import "./native.js" #*Euler's constant and the base of natural logarithms; approximately 2.718. set E 2.718281828459045 diff --git a/packages/docs/out/DateTime.md b/packages/docs/out/DateTime.md index dc4d0df..4095478 100644 --- a/packages/docs/out/DateTime.md +++ b/packages/docs/out/DateTime.md @@ -3,6 +3,15 @@ # Table of Contents - [Scope: DateTime](#scope-DateTime) + - [`SECONDS_PER_MINUTE`](#SECONDS_PER_MINUTE) + - [`MINUTES_PER_HOUR`](#MINUTES_PER_HOUR) + - [`HOURS_PER_DAY`](#HOURS_PER_DAY) + - [`DAYS_PER_WEEK`](#DAYS_PER_WEEK) + - [`SECOND`](#SECOND) + - [`MINUTE`](#MINUTE) + - [`HOUR`](#HOUR) + - [`DAY`](#DAY) + - [`WEEK`](#WEEK) - [`getDay date`](#getDay-date) - [`getFullYear date`](#getFullYear-date) - [`getHours date`](#getHours-date) @@ -35,6 +44,44 @@ DateTime utilities +## Variables + +### `SECONDS_PER_MINUTE` + +Number of seconds in a minute + +### `MINUTES_PER_HOUR` + +Number of minutes in an hour + +### `HOURS_PER_DAY` + +Number of hours in a day + +### `DAYS_PER_WEEK` + +Number of days in a week + +### `SECOND` + +Number of milliseconds in a second + +### `MINUTE` + +Number of milliseconds in a minute + +### `HOUR` + +Number of milliseconds in an hour + +### `DAY` + +Number of milliseconds in a day + +### `WEEK` + +Number of milliseconds in a week + ## Rules ### `getDay date` @@ -144,41 +191,3 @@ Returns the primitive value of a Date object ### `dayOfYear date` Get number of the day in the year @return Number of the day in year - -## Variables - -### `SECONDS_PER_MINUTE` - -Number of seconds in a minute - -### `MINUTES_PER_HOUR` - -Number of minutes in an hour - -### `HOURS_PER_DAY` - -Number of hours in a day - -### `DAYS_PER_WEEK` - -Number of days in a week - -### `SECOND` - -Number of milliseconds in a second - -### `MINUTE` - -Number of milliseconds in a minute - -### `HOUR` - -Number of milliseconds in an hour - -### `DAY` - -Number of milliseconds in a day - -### `WEEK` - -Number of milliseconds in a week diff --git a/packages/docs/out/Math.md b/packages/docs/out/Math.md index a33f865..cea6894 100644 --- a/packages/docs/out/Math.md +++ b/packages/docs/out/Math.md @@ -3,6 +3,14 @@ # Table of Contents - [Scope: Math](#scope-Math) + - [`E`](#E) + - [`LN10`](#LN10) + - [`LN2`](#LN2) + - [`LOG10E`](#LOG10E) + - [`LOG2E`](#LOG2E) + - [`PI`](#PI) + - [`SQRT1_2`](#SQRT1_2) + - [`SQRT2`](#SQRT2) - [`acos x`](#acos-x) - [`acosh x`](#acosh-x) - [`asin x`](#asin-x) @@ -40,6 +48,40 @@ Standard Math functions +## Variables + +### `E` + +Euler's constant and the base of natural logarithms; approximately 2.718. + +### `LN10` + +Natural logarithm of 2; approximately 0.693. + +### `LN2` + +Natural logarithm of 10; approximately 2.303. + +### `LOG10E` + +Base-2 logarithm of E; approximately 1.443. + +### `LOG2E` + +Base-10 logarithm of E; approximately 0.434. + +### `PI` + +Ratio of the a circle's circumference to its diameter; approximately 3.14159. + +### `SQRT1_2` + +Square root of ½ (or equivalently, 1/√2); approximately 0.707. + +### `SQRT2` + +Square root of 2; approximately 1.414. + ## Rules ### `acos x` @@ -169,38 +211,3 @@ Returns the hyperbolic tangent of x. ### `trunc x` Returns the integer portion of x, removing any fractional digits. - -## Variables - -### `Math` - -, , -Euler's constant and the base of natural logarithms; approximately 2.718. - -### `LN10` - -Natural logarithm of 2; approximately 0.693. - -### `LN2` - -Natural logarithm of 10; approximately 2.303. - -### `LOG10E` - -Base-2 logarithm of E; approximately 1.443. - -### `LOG2E` - -Base-10 logarithm of E; approximately 0.434. - -### `PI` - -Ratio of the a circle's circumference to its diameter; approximately 3.14159. - -### `SQRT1_2` - -Square root of ½ (or equivalently, 1/√2); approximately 0.707. - -### `SQRT2` - -Square root of 2; approximately 1.414. diff --git a/packages/docs/plugins/markdownGen.js b/packages/docs/plugins/markdownGen.js index d5e8155..0b701ba 100644 --- a/packages/docs/plugins/markdownGen.js +++ b/packages/docs/plugins/markdownGen.js @@ -39,11 +39,12 @@ module.exports = async (docTree, file) => { // mapping of a rulename to a link slug const ruleMap = {}; + const varMap = {}; + //Build Documentation Directory (Inspired by https://nodejs.org/api/fs.html) readmeLines.push( bullet( Object.keys(docTree).map((scope) => { - // TODO: Will break if multiple rules have the same name in different scopes const rules = Object.keys(docTree[scope].rules).map((rule) => { let text = rule.trim(); let slug = rule.trim(); @@ -60,11 +61,14 @@ module.exports = async (docTree, file) => { return link(shortcode(text), `#${slug}`); }); + const vars = Object.keys(docTree[scope].vars || {}).map((variable) => { + return link(shortcode(variable), `#${variable}`); + }); const configVars = Object.keys( docTree[scope].config || {} ).map((configVar) => link(`Config: ${configVar}`, `#${configVar}`)); - const entries = bullet([...configVars, ...rules], 1); + const entries = bullet([...vars, ...configVars, ...rules], 1); return `${link( `Scope: ${scope.trim()}`, `#scope-${scope.trim()}` @@ -82,6 +86,16 @@ module.exports = async (docTree, file) => { readmeLines.push(line); const { vars, rules, config } = docTree[scope]; + if (vars && Object.keys(vars).length) { + readmeLines.push(h2("Variables")); + const varLines = Object.keys(vars).map((variable) => { + const { help, desc, type } = vars[variable]; + return `${h3(shortcode(variable))}${type ? "\n" + italics(type) : ""}${ + desc ? "\n" + desc : help ? "\n" + help : "" + }`; + }); + readmeLines.push(...varLines); + } if (rules && Object.keys(rules).length) { readmeLines.push(h2("Rules")); const ruleLines = Object.keys(rules).map((rule) => { @@ -139,16 +153,6 @@ module.exports = async (docTree, file) => { }); readmeLines.push(bullet(configLines)); } - if (vars && Object.keys(vars).length) { - readmeLines.push(h2("Variables")); - const varLines = Object.keys(vars).map((variable) => { - const { help, desc, type } = vars[variable]; - return `${h3(shortcode(variable))}${type ? "\n" + italics(type) : ""}${ - desc ? "\n" + desc : help ? "\n" + help : "" - }`; - }); - readmeLines.push(...varLines); - } }); if (typeof file === "string") { From 4130efb49022f632e2195ab6317f151f4781c074 Mon Sep 17 00:00:00 2001 From: Pranay Prakash Date: Mon, 14 Sep 2020 17:55:57 -0700 Subject: [PATCH 14/16] rm docs' out from git --- packages/docs/out/DateTime.md | 193 ----------------- packages/docs/out/Math.md | 213 ------------------- packages/docs/out/rule.md | 386 ---------------------------------- 3 files changed, 792 deletions(-) delete mode 100644 packages/docs/out/DateTime.md delete mode 100644 packages/docs/out/Math.md delete mode 100644 packages/docs/out/rule.md diff --git a/packages/docs/out/DateTime.md b/packages/docs/out/DateTime.md deleted file mode 100644 index 4095478..0000000 --- a/packages/docs/out/DateTime.md +++ /dev/null @@ -1,193 +0,0 @@ -> This was generated using BrowseDoc which is still very much a work in progress - -# Table of Contents - -- [Scope: DateTime](#scope-DateTime) - - [`SECONDS_PER_MINUTE`](#SECONDS_PER_MINUTE) - - [`MINUTES_PER_HOUR`](#MINUTES_PER_HOUR) - - [`HOURS_PER_DAY`](#HOURS_PER_DAY) - - [`DAYS_PER_WEEK`](#DAYS_PER_WEEK) - - [`SECOND`](#SECOND) - - [`MINUTE`](#MINUTE) - - [`HOUR`](#HOUR) - - [`DAY`](#DAY) - - [`WEEK`](#WEEK) - - [`getDay date`](#getDay-date) - - [`getFullYear date`](#getFullYear-date) - - [`getHours date`](#getHours-date) - - [`getMilliseconds date`](#getMilliseconds-date) - - [`getMinutes date`](#getMinutes-date) - - [`getMonth date`](#getMonth-date) - - [`getSeconds date`](#getSeconds-date) - - [`getTime date`](#getTime-date) - - [`getTimezoneOffset date`](#getTimezoneOffset-date) - - [`getUTCDate date`](#getUTCDate-date) - - [`getUTCDay date`](#getUTCDay-date) - - [`getUTCFullYear date`](#getUTCFullYear-date) - - [`getUTCHours date`](#getUTCHours-date) - - [`getUTCMilliseconds date`](#getUTCMilliseconds-date) - - [`getUTCMinutes date`](#getUTCMinutes-date) - - [`getUTCMonth date`](#getUTCMonth-date) - - [`getUTCSeconds date`](#getUTCSeconds-date) - - [`toDateString date`](#toDateString-date) - - [`toISOString date`](#toISOString-date) - - [`toLocaleDateString date tz`](#toLocaleDateString-date-tz) - - [`toLocaleString date tz`](#toLocaleString-date-tz) - - [`toLocaleTimeString date tz`](#toLocaleTimeString-date-tz) - - [`toString date`](#toString-date) - - [`toTimeString date`](#toTimeString-date) - - [`toUTCString date`](#toUTCString-date) - - [`valueOf date`](#valueOf-date) - - [`dayOfYear date`](#dayOfYear-date) - -## Scope `DateTime` - -DateTime utilities - -## Variables - -### `SECONDS_PER_MINUTE` - -Number of seconds in a minute - -### `MINUTES_PER_HOUR` - -Number of minutes in an hour - -### `HOURS_PER_DAY` - -Number of hours in a day - -### `DAYS_PER_WEEK` - -Number of days in a week - -### `SECOND` - -Number of milliseconds in a second - -### `MINUTE` - -Number of milliseconds in a minute - -### `HOUR` - -Number of milliseconds in an hour - -### `DAY` - -Number of milliseconds in a day - -### `WEEK` - -Number of milliseconds in a week - -## Rules - -### `getDay date` - -Returns the day of the week (0–6) for the specified date according to local time. - -### `getFullYear date` - -Returns the day of the week (0–6) for the specified date according to local time. - -### `getHours date` - -Returns the hour (0–23) in the specified date according to local time. - -### `getMilliseconds date` - -Returns the milliseconds (0–999) in the specified date according to local time. - -### `getMinutes date` - -Returns the minutes (0–59) in the specified date according to local time. - -### `getMonth date` - -Returns the month (0–11) in the specified date according to local time. - -### `getSeconds date` - -Returns the seconds (0–59) in the specified date according to local time. - -### `getTime date` - -Returns the numeric value of the specified date as the number of milliseconds since January 1, 1970, 00:00:00 UTC. (Negative values are returned for prior times.) - -### `getTimezoneOffset date` - -Returns the time-zone offset in minutes for the current locale. - -### `getUTCDate date` - -Returns the day (date) of the month (1–31) in the specified date according to universal time. - -### `getUTCDay date` - -Returns the day of the week (0–6) in the specified date according to universal time. - -### `getUTCFullYear date` - -Returns the year (4 digits for 4-digit years) in the specified date according to universal time. - -### `getUTCHours date` - -Returns the hours (0–23) in the specified date according to universal time. - -### `getUTCMilliseconds date` - -Returns the milliseconds (0–999) in the specified date according to universal time. - -### `getUTCMinutes date` - -Returns the minutes (0–59) in the specified date according to universal time. - -### `getUTCMonth date` - -Returns the month (0–11) in the specified date according to universal time. - -### `getUTCSeconds date` - -Returns the seconds (0–59) in the specified date according to universal time. - -### `toDateString date` - -Returns the "date" portion of the Date as a human-readable string like 'Thu Apr 12 2018'. - -### `toISOString date` - -Converts a date to a string following the ISO 8601 Extended Format. - -### `toLocaleDateString date tz` - -Returns a string with a locality sensitive representation of the date portion of this date based on system settings. - -### `toLocaleString date tz` - -Returns a string with a locality-sensitive representation of this date - -### `toLocaleTimeString date tz` - -Returns a string with a locality-sensitive representation of the time portion of this date, based on system settings. - -### `toString date` - -Returns a string representing the specified Date object - -### `toTimeString date` - -Returns the "time" portion of the Date as a human-readable string. - -### `toUTCString date` - -Converts a date to a string using the UTC timezone. - -### `valueOf date` - -Returns the primitive value of a Date object - -### `dayOfYear date` - -Get number of the day in the year @return Number of the day in year diff --git a/packages/docs/out/Math.md b/packages/docs/out/Math.md deleted file mode 100644 index cea6894..0000000 --- a/packages/docs/out/Math.md +++ /dev/null @@ -1,213 +0,0 @@ -> This was generated using BrowseDoc which is still very much a work in progress - -# Table of Contents - -- [Scope: Math](#scope-Math) - - [`E`](#E) - - [`LN10`](#LN10) - - [`LN2`](#LN2) - - [`LOG10E`](#LOG10E) - - [`LOG2E`](#LOG2E) - - [`PI`](#PI) - - [`SQRT1_2`](#SQRT1_2) - - [`SQRT2`](#SQRT2) - - [`acos x`](#acos-x) - - [`acosh x`](#acosh-x) - - [`asin x`](#asin-x) - - [`asinh x`](#asinh-x) - - [`atan x`](#atan-x) - - [`atanh x`](#atanh-x) - - [`atan2 y x`](#atan2-y-x) - - [`cbrt x`](#cbrt-x) - - [`ceil x`](#ceil-x) - - [`clz32 x`](#clz32-x) - - [`cos x`](#cos-x) - - [`cosh x`](#cosh-x) - - [`exp x`](#exp-x) - - [`expm1 x`](#expm1-x) - - [`floor x`](#floor-x) - - [`fround x`](#fround-x) - - [`hypot x y`](#hypot-x-y) - - [`imul x y`](#imul-x-y) - - [`log x`](#log-x) - - [`log1p x`](#log1p-x) - - [`log10 x`](#log10-x) - - [`log2 x`](#log2-x) - - [`pow x y`](#pow-x-y) - - [`random`](#random) - - [`round x`](#round-x) - - [`sign x`](#sign-x) - - [`sin x`](#sin-x) - - [`sinh x`](#sinh-x) - - [`sqrt x`](#sqrt-x) - - [`tan x`](#tan-x) - - [`tanh x`](#tanh-x) - - [`trunc x`](#trunc-x) - -## Scope `Math` - -Standard Math functions - -## Variables - -### `E` - -Euler's constant and the base of natural logarithms; approximately 2.718. - -### `LN10` - -Natural logarithm of 2; approximately 0.693. - -### `LN2` - -Natural logarithm of 10; approximately 2.303. - -### `LOG10E` - -Base-2 logarithm of E; approximately 1.443. - -### `LOG2E` - -Base-10 logarithm of E; approximately 0.434. - -### `PI` - -Ratio of the a circle's circumference to its diameter; approximately 3.14159. - -### `SQRT1_2` - -Square root of ½ (or equivalently, 1/√2); approximately 0.707. - -### `SQRT2` - -Square root of 2; approximately 1.414. - -## Rules - -### `acos x` - -Returns the arccosine of x. - -### `acosh x` - -Returns the hyperbolic arccosine of x. - -### `asin x` - -Returns the arcsine of x. - -### `asinh x` - -Returns the hyperbolic arcsine of a number. - -### `atan x` - -Returns the arctangent of x. - -### `atanh x` - -Returns the hyperbolic arctangent of x. - -### `atan2 y x` - -Returns the arctangent of the quotient of its arguments. - -### `cbrt x` - -Returns the cube root of x. - -### `ceil x` - -Returns the smallest integer greater than or equal to x. - -### `clz32 x` - -Returns the number of leading zeroes of the 32-bit integer x. - -### `cos x` - -Returns the cosine of x. - -### `cosh x` - -Returns the hyperbolic cosine of x. - -### `exp x` - -Returns E^x, where x is the argument, and E is Euler's constant (2.718…, the base of the natural logarithm). - -### `expm1 x` - -Returns subtracting 1 from exp(x). - -### `floor x` - -Returns the largest integer less than or equal to x. - -### `fround x` - -Returns the nearest single precision float representation of x. - -### `hypot x y` - -Returns the square root of the sum of squares of both arguments. TODO: support more than 2 arguments, like in the JS native version - -### `imul x y` - -Returns the result of the 32-bit integer multiplication of x and y. - -### `log x` - -Returns the natural logarithm (㏒e; also, ㏑) of x. - -### `log1p x` - -Returns the natural logarithm (㏒e; also ㏑) of 1 + x for the number x. - -### `log10 x` - -Returns the base-10 logarithm of x. - -### `log2 x` - -Returns the base-2 logarithm of x. - -### `pow x y` - -Returns base x to the exponent power y (that is, xy). - -### `random` - -Returns a pseudo-random number between 0 and 1. - -### `round x` - -Returns the value of the number x rounded to the nearest integer. - -### `sign x` - -Returns the sign of the x, indicating whether x is positive, negative, or zero. - -### `sin x` - -Returns the sine of x. - -### `sinh x` - -Returns the hyperbolic sine of x. - -### `sqrt x` - -Returns the positive square root of x. - -### `tan x` - -Returns the tangent of x. - -### `tanh x` - -Returns the hyperbolic tangent of x. - -### `trunc x` - -Returns the integer portion of x, removing any fractional digits. diff --git a/packages/docs/out/rule.md b/packages/docs/out/rule.md deleted file mode 100644 index 1cff588..0000000 --- a/packages/docs/out/rule.md +++ /dev/null @@ -1,386 +0,0 @@ -> This was generated using BrowseDoc which is still very much a work in progress - -# Table of Contents - -- [Scope: std](#scope-std) - - [`help`](#help) - - [`scope`](#scope) - - [`id value`](#id-value) - - [`get key`](#get-key) - - [`arr_get index array`](#arr_get-index-array) - - [`dict_get key dict`](#dict_get-key-dict) - - [`set key value`](#set-key-value) - - [`arr_set index value array`](#arr_set-index-value-array) - - [`dict_set key value dict`](#dict_set-key-value-dict) - - [`unset key`](#unset-key) - - [`dict_unset key dict`](#dict_unset-key-dict) - - [`update key value`](#update-key-value) - - [`push value dest`](#push-value-dest) - - [`pop dest`](#pop-dest) - - [`rule name body`](#rule-name-body) - - [`sleep ms`](#sleep-ms) - - [`print`](#print) - - [`if condition then thenRuleSet else elseRuleSet`](#if-condition-then-thenRuleSet-else-elseRuleSet) - - [`for iterator body`](#for-iterator-body) - - [`eval ruleset inject`](#eval-ruleset-inject) - - [`arr ruleset`](#arr-ruleset) - - [`dict ruleset`](#dict-ruleset) - - [`import`](#import) - - [`string value`](#string-value) - - [`len value`](#len-value) -- [Scope: rule](#scope-rule) - - [`bind`](#bind) - - [`return value`](#return-value) - -## Scope `std` - -This scope is available to every program and consists of all the core rules to write useful browse programs - -## Rules - -### `help` - -Run `help` in a repl, or add it to your code during debugging, to learn about all the rules you can use in a scope - -### `scope` - -Internal: this dumps the current JS scope to stdout for debugging - -### `id value` - -- `value` \<**T**\> Any value - -- Returns: \<**T**\> The value passed in, unchanged - -Returns whatever value is passed in. This is the _identity_ rule - -### `get key` - -- `key` \<**string**\> An identifer - -- Returns: \<**any**\> The value of `key` - -Resolves to the value of the variable `key` - -> The shorthand for this rule is `$`. So, `$someVar` is the -> same as `(get someVar)`. The shorthand syntax is the preferred way to -> read a value. - -### `arr_get index array` - -- `index` \<**number**\> A valid 0-indexed position in the `array` - -- `array` \<**arr\**\> The array to lookup - -- Returns: \<**T**\> The element at `index` in the `array` - -Get the element at `index` in the `array` - -### `dict_get key dict` - -- `key` \<**K**\> A valid key in the dictionary - -- `dict` \<**dict\**\> The dictionary to lookup - -- Returns: \<**V**\> The value of `key` in the `dict` dictionary - -Get the value of `key` in the `dict` dictionary - -### `set key value` - -- `key` \<**string**\> An identifer (a.k.a variable name) - -- `value` \<**T**\> The value to set the variable to - -- Returns: \<**T**\> value - -sets to the value of the variable `key` to `value` - -> 'set' always creates/updates the variable in the immediate/local scope. -> If a variable with the same name exists in a higher scope, it will be -> 'shadowed', not updated. To update a variable instead of creating a -> new one, use the [update](#update-key-value) rule. - -### `arr_set index value array` - -- `index` \<**number**\> A valid 0-indexed position in the `array` - -- `value` \<**T**\> The value to set in the array - -- `array` \<**arr\**\> The array to write to - -- Returns: \<**T**\> The value - -Set the element at `index` in the `array` to `value` - -> To increase the size of the array, see [push](#push-value-dest) or use the `array` library - -### `dict_set key value dict` - -- `key` \<**K**\> The key in the dictionary to set - -- `value` \<**V**\> The value to set `key` to in the dictionary - -- `dict` \<**dict\**\> The dictionary to write to - -- Returns: \<**V**\> The value - -Set the value of `key` in the `dict` dictionary - -### `unset key` - -- `key` \<**string**\> An identifer - -- Returns: \<**any**\> The value stored in the variable key - -Unset the variable 'key' - -### `dict_unset key dict` - -- `key` \<**K**\> A valid key in dict - -- `dict` \<**dict\**\> The dictionary to update - -- Returns: \<**V**\> The value from the deleted pair - -Delete the key-value record matching `key` from the dictionary `dict` - -### `update key value` - -- `key` \<**string**\> An identifer (a.k.a variable name) - -- `value` \<**V**\> The value to set the variable to - -- Returns: \<**V**\> value - -Updates the variable 'key' to the value 'value' - -> 'update' updates the value for the variable `key` in the closest ancestor scope. -> If a variable with the name `key` already exists in the current scope, then -> `update` throws an error. You should use [set](#set-key-value) instead for such cases. - -### `push value dest` - -- `value` \<**T**\> The value to push - -- `dest` \<**arr\**\> The array to push to - -- Returns: \<**number**\> The number of elements in the array after pushing to it - -Push an element to the back of an array - -### `pop dest` - -- `dest` \<**arr\**\> The array to remove an element from - -- Returns: \<**T**\> The value of the element removed - -Remove the element at the back of the array and return it - -### `rule name body` - -- `name` \<**string**\> An identifer to name the rule - -- `body` \<**RuleSet**\> The behavior that should be executed when rule is called with arguments - -- Returns: \<**Rule**\> TODO: This value cannot be used by browse and is only understood by the runtime. Provide a better value - -Define a new rule 'name'. The 'body' has access to two additional rules, [bind](#bind) and [return](#return-value) used to take arguments and return a value - -### `sleep ms` - -- `ms` \<**number**\> The number of milliseconds to sleep for - -- Returns: \<**number**\> ms - -Sleep for 'ms' milliseconds - -> This is a blocking rule - -### `print` - -- Returns: \<**any**\> The value of the last argument passed to print - -Print values to stdout - -``` -# Hello World -print Hello World - -# Since 'print' evaluates to the last argument passed in, it makes -# it easy to compose `print` when debuggin complicated expressions -rule fact { - bind x - if $x <= 1 then { return $x } else { - return (print $x + '! =' $x * (fact $x - 1)) - } -} -fact 4 - -# output = -# 2! = 2 -# 3! = 6 -# 4! = 24 - -``` - -### `if condition then thenRuleSet else elseRuleSet` - -- `condition` \<**any**\> The condition to test - -- `then` \<**"then"**\> The string "then" - -- `thenRuleSet` \<**RuleSet**\> The ruleset that will be executed if condition evaluates to true - ? -- `else` \<**"else"**\> The string "else" - ? -- `elseRuleSet` \<**RuleSet**\> The ruleset that will be executed if condition evaluates to false - -- Returns: \<**any**\> The result of the RuleSet that was evaluated code. `nil` is no `else` claus is provided - -If 'condition' is truthy, evaluate the 'then' RuleSet, else evaluate the 'else' rule set - -> If `else` and `elseRuleSet` are not provided, then nothing is evaluated if the `condition` -> is falsy. The entire `if` rule will evaluate to `nil` in this case - -``` -if ($grade > 60) then { print pass -``` - -### `for iterator body` - -- `iterator` \<**RuleSet**\> The iteration criteria - -- `body` \<**RuleSet**\> The body of the loop - -- Returns: \<**nil**\> nil (TODO: Should return the value of the last evaluated statement, or the number of iterations?) - -Execute the `body` while the `test` expressions in the `interator` do not fail - -> The contents of the iterator is split into multiple parts: -> -> - The very first rule is evaluated once, at the beginning, to setup the loop. -> Usually used to set a iteration variable -> - The remaining rules, except the last rule, are evaulated at the start of each -> rule. A `test` rule is available here that causes the loop to end if the first -> argument passed to `test` is falsy -> - The last rule is run at the end of each loop, i.e. affter the `body` is evaluated, -> but before the `test` rules (previous point) are evaluated again. Usually use to -> increment the iteration variable defined in point 1 - -``` -for { set i 2; test $i < 5; set i $i + 1 } { print loop $i } -``` - -### `eval ruleset inject` - -- `ruleset` \<**RuleSet**\> The RuleSet to evaluate - ? -- `inject` \<**RuleSet**\> A RuleSet that is evaluated in the scope before the ruleset is evaluated - -- Returns: \<**any**\> The result of evaluating the ruleset - -Evaluate a RuleSet. Optionally, inject variables and additional rules into the evaluation context/scope - -> inject is used to add additional variables and rules that can be used by the Ruleset -> This is the "explicit" form of scope injection that's used to make a pleasant experience -> for someone using a given library. See `examples/advanced/custom_rules.browse` in the browse -> repo to see some good examples for this - -``` -# See https://github.com/windsorio/browse/blob/master/examples/advanced/custom_rules.browse - -``` - -### `arr ruleset` - -- `ruleset` \<**RuleSet**\> The RuleSet used to instantiate the array - -- Returns: \<**arr\**\> The array - -Create an Array from a RuleSet - -> `arr` creates a new array, and then evaluates the RuleSet -> A rule called `el` is available inside this RuleSet. It takes one argument -> Each `el` call adds that element to the array before returning the final -> array. -> -> `e` and `_` are aliases for `el` - -``` -set a1 (arr { _ 1; _ 2; _ 3 }) - -# nested arrays -set a2 (arr { - _ (arr { - _ 1 - }) -}) - -``` - -### `dict ruleset` - -- `ruleset` \<**RuleSet**\> The RuleSet used to instantiate the dictionary - -- Returns: \<**dict\**\> The dictionary - -Create a Dictionary from a RuleSet - -> `dict` creates a new dictionary, and then evaluates the RuleSet -> A rule called `record` is available inside this RuleSet. It takes two arguments, -> a `key` and `value`. Each `record` call adds a new record to the dictionary -> mapping the `key` to the `value`. The final dictionary is `returned`. -> -> `r` and `_` are aliases for `record` - -``` -set o1 (dict { _ k1 v1; _ k2 v2 }) - -# nested dictionaries -set o2 (dict { - _ k1 (dict { - _ k2 v2 - }) -}) - -``` - -### `import` - -Import a module. Read the [Browse Modules](#) guide for more info (TODO) - -### `string value` - -- `value` \<**any**\> Any value - -Serialize any value as a string - -### `len value` - -- `value` \<**string | array\**\> A string or array - -Get the length of the string or number of elements in an array - -## Scope `rule` - -## Rules - -### `bind` - -- Returns: \<**any**\> nil - -'bind' lets the rule accept arguments. Strings passed to bind are used to assign variables that track the incoming values - -``` -# take 2 arguments and return the sum rule add { bind x y; return $x + $y } # accept options rule add2 { bind(print) x y set z $x + $y if $print then { print $z } else { return $z } } -``` - -### `return value` - -- `value` \<**T**\> The value to return -- Returns: \<**T**\> The value passed in, unchanged - -'return' is often used to make the return value for a rule explicit. It's often unnecessary however since every rule uses the last evaluated value in its body as the return value anyway. - -> The return rule doesn't work like `return` in other languages. `return` is just an alias for [id](#id-value) since the last value in a RuleSet is the implicit return value of the RuleSet. For example `rule f { return foo return bar }` In browse, this is valid and the return value is "bar". `return foo` is the same as `id foo` Which basically does nothing (a.k.a it's a no-op). and the last rule in the body evaluates to "bar" From d655cd8157f335a32741435b97da3c87d631314a Mon Sep 17 00:00:00 2001 From: Pranay Prakash Date: Mon, 14 Sep 2020 18:01:36 -0700 Subject: [PATCH 15/16] fix formatter: null -> nil --- packages/core/stdlib/math/main.browse | 2 +- packages/format/lib/language/printer.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/core/stdlib/math/main.browse b/packages/core/stdlib/math/main.browse index 372028e..98d9fa0 100644 --- a/packages/core/stdlib/math/main.browse +++ b/packages/core/stdlib/math/main.browse @@ -57,7 +57,7 @@ rule atanh { bind x; return (native:fn atanh $x) } #*Returns the arctangent of the quotient of its arguments. rule atan2 { bind y x; return (native:fn atan2 $y $x) } #*Returns the cube root of x. -rule cbrt { bind x; return (native:fn cbrt $x) }a +rule cbrt { bind x; return (native:fn cbrt $x) } #*Returns the smallest integer greater than or equal to x. rule ceil { bind x; return (native:fn ceil $x) } #*Returns the number of leading zeroes of the 32-bit integer x. diff --git a/packages/format/lib/language/printer.js b/packages/format/lib/language/printer.js index db34b1a..3366a39 100644 --- a/packages/format/lib/language/printer.js +++ b/packages/format/lib/language/printer.js @@ -125,7 +125,9 @@ function genericPrint(path, options, print) { return "opt"; } case "Literal": { - if (typeof n.value === "string") { + if (n.value === null) { + return "nil"; + } else if (typeof n.value === "string") { return concat([n.quoteType, n.value, n.quoteType]); } else { return String(n.value); From c2297466a4767960d50f1414f547716c18d552d5 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 19 Sep 2020 03:20:53 -0400 Subject: [PATCH 16/16] Added sub scopes --- packages/core/lib/std.js | 2 + packages/core/stdlib/datetime/main.browse | 74 ++--- packages/core/stdlib/math/main.browse | 87 +++-- packages/docs/out/rule.md | 386 ---------------------- packages/docs/out/std.md | 33 +- packages/docs/parsers/common.js | 2 +- packages/docs/parsers/js.js | 37 ++- packages/docs/plugins/markdownGen.js | 54 ++- 8 files changed, 158 insertions(+), 517 deletions(-) delete mode 100644 packages/docs/out/rule.md diff --git a/packages/core/lib/std.js b/packages/core/lib/std.js index 81f6f38..6097d24 100644 --- a/packages/core/lib/std.js +++ b/packages/core/lib/std.js @@ -622,6 +622,7 @@ const defRule = (evalRuleSet) => (scope) => (_opts) => (name, body) => { /** * @rule { bind } * @scope { rule } + * @parent { std } * @desc { * **Only used within a {@link rule\} body** * 'bind' lets the rule accept arguments. Strings passed to bind are used to @@ -667,6 +668,7 @@ const defRule = (evalRuleSet) => (scope) => (_opts) => (name, body) => { /** * @rule { return } * @scope { rule } + * @parent { std } * @desc { * **Only used within a {@link rule\} body** * 'return' is often used to make the return value for a rule explicit. It's often diff --git a/packages/core/stdlib/datetime/main.browse b/packages/core/stdlib/datetime/main.browse index 84f73fe..efd33a9 100644 --- a/packages/core/stdlib/datetime/main.browse +++ b/packages/core/stdlib/datetime/main.browse @@ -1,27 +1,27 @@ -#* @name { DateTime } +#* @name { DateTime } # @scope { DateTime utilities } import math import "./native.js" -#*Number of seconds in a minute +#* Number of seconds in a minute set SECONDS_PER_MINUTE 60 -#*Number of minutes in an hour +#* Number of minutes in an hour set MINUTES_PER_HOUR 60 -#*Number of hours in a day +#* Number of hours in a day set HOURS_PER_DAY 24 -#*Number of days in a week +#* Number of days in a week set DAYS_PER_WEEK 7 -#*Number of milliseconds in a second +#* Number of milliseconds in a second set SECOND 1000 -#*Number of milliseconds in a minute +#* Number of milliseconds in a minute set MINUTE $SECOND * $SECONDS_PER_MINUTE -#*Number of milliseconds in an hour +#* Number of milliseconds in an hour set HOUR $MINUTE * $MINUTES_PER_HOUR -#*Number of milliseconds in a day +#* Number of milliseconds in a day set DAY $HOUR * $HOURS_PER_DAY -#*Number of milliseconds in a week +#* Number of milliseconds in a week set WEEK $DAY * $DAYS_PER_WEEK # A date looks like this: @@ -36,71 +36,71 @@ rule Date { bind a b c d e f g; return (native:Date $a $b $c $d $e $f $g) } #################################### ### The Native JS Date functions ### #################################### -#*Returns the day of the month (1–31) for the specified date according to local time. +#* Returns the day of the month (1–31) for the specified date according to local time. rule getDate { bind date; return (native:date_fn $date getDate) } -#*Returns the day of the week (0–6) for the specified date according to local time. +#* Returns the day of the week (0–6) for the specified date according to local time. rule getDay { bind date; return (native:date_fn $date getDay) } -#*Returns the day of the week (0–6) for the specified date according to local time. +#* Returns the day of the week (0–6) for the specified date according to local time. rule getFullYear { bind date; return (native:date_fn $date getFullYear) } -#*Returns the hour (0–23) in the specified date according to local time. +#* Returns the hour (0–23) in the specified date according to local time. rule getHours { bind date; return (native:date_fn $date getHours) } -#*Returns the milliseconds (0–999) in the specified date according to local time. +#* Returns the milliseconds (0–999) in the specified date according to local time. rule getMilliseconds { bind date; return (native:date_fn $date getMilliseconds) } -#*Returns the minutes (0–59) in the specified date according to local time. +#* Returns the minutes (0–59) in the specified date according to local time. rule getMinutes { bind date; return (native:date_fn $date getMinutes) } -#*Returns the month (0–11) in the specified date according to local time. +#* Returns the month (0–11) in the specified date according to local time. rule getMonth { bind date; return (native:date_fn $date getMonth) } -#*Returns the seconds (0–59) in the specified date according to local time. +#* Returns the seconds (0–59) in the specified date according to local time. rule getSeconds { bind date; return (native:date_fn $date getSeconds) } -#*Returns the numeric value of the specified date as the number of milliseconds since January 1, 1970, 00:00:00 UTC. (Negative values are returned for prior times.) +#* Returns the numeric value of the specified date as the number of milliseconds since January 1, 1970, 00:00:00 UTC. (Negative values are returned for prior times.) rule getTime { bind date; return (native:date_fn $date getTime) } -#*Returns the time-zone offset in minutes for the current locale. +#* Returns the time-zone offset in minutes for the current locale. rule getTimezoneOffset { bind date; return (native:date_fn $date getTimezoneOffset) } -#*Returns the day (date) of the month (1–31) in the specified date according to universal time. +#* Returns the day (date) of the month (1–31) in the specified date according to universal time. rule getUTCDate { bind date; return (native:date_fn $date getUTCDate) } -#*Returns the day of the week (0–6) in the specified date according to universal time. +#* Returns the day of the week (0–6) in the specified date according to universal time. rule getUTCDay { bind date; return (native:date_fn $date getUTCDay) } -#*Returns the year (4 digits for 4-digit years) in the specified date according to universal time. +#* Returns the year (4 digits for 4-digit years) in the specified date according to universal time. rule getUTCFullYear { bind date; return (native:date_fn $date getUTCFullYear) } -#*Returns the hours (0–23) in the specified date according to universal time. +#* Returns the hours (0–23) in the specified date according to universal time. rule getUTCHours { bind date; return (native:date_fn $date getUTCHours) } -#*Returns the milliseconds (0–999) in the specified date according to universal time. +#* Returns the milliseconds (0–999) in the specified date according to universal time. rule getUTCMilliseconds { bind date; return (native:date_fn $date getUTCMilliseconds) } -#*Returns the minutes (0–59) in the specified date according to universal time. +#* Returns the minutes (0–59) in the specified date according to universal time. rule getUTCMinutes { bind date; return (native:date_fn $date getUTCMinutes) } -#*Returns the month (0–11) in the specified date according to universal time. +#* Returns the month (0–11) in the specified date according to universal time. rule getUTCMonth { bind date; return (native:date_fn $date getUTCMonth) } -#*Returns the seconds (0–59) in the specified date according to universal time. +#* Returns the seconds (0–59) in the specified date according to universal time. rule getUTCSeconds { bind date; return (native:date_fn $date getUTCSeconds) } -#*Returns the "date" portion of the Date as a human-readable string like 'Thu Apr 12 2018'. +#* Returns the "date" portion of the Date as a human-readable string like 'Thu Apr 12 2018'. rule toDateString { bind date; return (native:date_fn $date toDateString) } -#*Converts a date to a string following the ISO 8601 Extended Format. +#* Converts a date to a string following the ISO 8601 Extended Format. rule toISOString { bind date; return (native:date_fn $date toISOString) } -#*Returns a string with a locality sensitive representation of the date portion of this date based on system settings. +#* Returns a string with a locality sensitive representation of the date portion of this date based on system settings. rule toLocaleDateString { bind date tz; return (native:date_fn $date toLocaleDateString $tz) } -#*Returns a string with a locality-sensitive representation of this date +#* Returns a string with a locality-sensitive representation of this date rule toLocaleString { bind date tz; return (native:date_fn $date toLocaleString $tz) } -#*Returns a string with a locality-sensitive representation of the time portion of this date, based on system settings. +#* Returns a string with a locality-sensitive representation of the time portion of this date, based on system settings. rule toLocaleTimeString { bind date tz; return (native:date_fn $date toLocaleTimeString $tz) } -#*Returns a string representing the specified Date object +#* Returns a string representing the specified Date object rule toString { bind date; return (native:date_fn $date toString) } -#*Returns the "time" portion of the Date as a human-readable string. +#* Returns the "time" portion of the Date as a human-readable string. rule toTimeString { bind date; return (native:date_fn $date toTimeString) } -#*Converts a date to a string using the UTC timezone. +#* Converts a date to a string using the UTC timezone. rule toUTCString { bind date; return (native:date_fn $date toUTCString) } -#*Returns the primitive value of a Date object +#* Returns the primitive value of a Date object rule valueOf { bind date; return (native:date_fn $date valueOf) } ##################################### diff --git a/packages/core/stdlib/math/main.browse b/packages/core/stdlib/math/main.browse index 372028e..b60cc54 100644 --- a/packages/core/stdlib/math/main.browse +++ b/packages/core/stdlib/math/main.browse @@ -1,30 +1,29 @@ #* @scope { Standard Math functions } # @name { Math } -# TODO: This is a bit hacky. If the @name is called below the import it will be attributed to E rather than to the scope. import "./native.js" -#*Euler's constant and the base of natural logarithms; approximately 2.718. +#* Euler's constant and the base of natural logarithms; approximately 2.718. set E 2.718281828459045 -#*Natural logarithm of 2; approximately 0.693. +#* Natural logarithm of 2; approximately 0.693. set LN10 2.302585092994046 -#*Natural logarithm of 10; approximately 2.303. +#* Natural logarithm of 10; approximately 2.303. set LN2 0.6931471805599453 -#*Base-2 logarithm of E; approximately 1.443. +#* Base-2 logarithm of E; approximately 1.443. set LOG10E 0.4342944819032518 -#*Base-10 logarithm of E; approximately 0.434. +#* Base-10 logarithm of E; approximately 0.434. set LOG2E 1.4426950408889634 -#*Ratio of the a circle's circumference to its diameter; approximately 3.14159. +#* Ratio of the a circle's circumference to its diameter; approximately 3.14159. set PI 3.141592653589793 -#*Square root of ½ (or equivalently, 1/√2); approximately 0.707. +#* Square root of ½ (or equivalently, 1/√2); approximately 0.707. set SQRT1_2 0.7071067811865476 -#*Square root of 2; approximately 1.414. +#* Square root of 2; approximately 1.414. set SQRT2 1.4142135623730951 # built in number functions @@ -40,76 +39,76 @@ rule toPrecision { } # Math.* fns -#*Returns the absolute value of x. +#* Returns the absolute value of x. rule abs { bind x; return (native:fn abs $x) } -#*Returns the arccosine of x. +#* Returns the arccosine of x. rule acos { bind x; return (native:fn acos $x) } -#*Returns the hyperbolic arccosine of x. +#* Returns the hyperbolic arccosine of x. rule acosh { bind x; return (native:fn acosh $x) } -#*Returns the arcsine of x. +#* Returns the arcsine of x. rule asin { bind x; return (native:fn asin $x) } -#*Returns the hyperbolic arcsine of a number. +#* Returns the hyperbolic arcsine of a number. rule asinh { bind x; return (native:fn asinh $x) } -#*Returns the arctangent of x. +#* Returns the arctangent of x. rule atan { bind x; return (native:fn atan $x) } -#*Returns the hyperbolic arctangent of x. +#* Returns the hyperbolic arctangent of x. rule atanh { bind x; return (native:fn atanh $x) } -#*Returns the arctangent of the quotient of its arguments. +#* Returns the arctangent of the quotient of its arguments. rule atan2 { bind y x; return (native:fn atan2 $y $x) } -#*Returns the cube root of x. +#* Returns the cube root of x. rule cbrt { bind x; return (native:fn cbrt $x) }a -#*Returns the smallest integer greater than or equal to x. +#* Returns the smallest integer greater than or equal to x. rule ceil { bind x; return (native:fn ceil $x) } -#*Returns the number of leading zeroes of the 32-bit integer x. +#* Returns the number of leading zeroes of the 32-bit integer x. rule clz32 { bind x; return (native:fn clz32 $x) } -#*Returns the cosine of x. +#* Returns the cosine of x. rule cos { bind x; return (native:fn cos $x) } -#*Returns the hyperbolic cosine of x. +#* Returns the hyperbolic cosine of x. rule cosh { bind x; return (native:fn cosh $x) } -#*Returns E^x, where x is the argument, and E is Euler's constant (2.718…, the base of the natural logarithm). +#* Returns E^x, where x is the argument, and E is Euler's constant (2.718…, the base of the natural logarithm). rule exp { bind x; return (native:fn exp $x) } -#*Returns subtracting 1 from exp(x). +#* Returns subtracting 1 from exp(x). rule expm1 { bind x; return (native:fn expm1 $x) } -#*Returns the largest integer less than or equal to x. +#* Returns the largest integer less than or equal to x. rule floor { bind x; return (native:fn floor $x) } -#*Returns the nearest single precision float representation of x. +#* Returns the nearest single precision float representation of x. rule fround { bind x; return (native:fn fround $x) } -#*Returns the square root of the sum of squares of both arguments. +#* Returns the square root of the sum of squares of both arguments. # TODO: support more than 2 arguments, like in the JS native version rule hypot { bind x y; return (native:fn hypot $x $y) } -#*Returns the result of the 32-bit integer multiplication of x and y. +#* Returns the result of the 32-bit integer multiplication of x and y. rule imul { bind x y; return (native:fn imul $x $y) } -#*Returns the natural logarithm (㏒e; also, ㏑) of x. +#* Returns the natural logarithm (㏒e; also, ㏑) of x. rule log { bind x; return (native:fn log $x) } -#*Returns the natural logarithm (㏒e; also ㏑) of 1 + x for the number x. +#* Returns the natural logarithm (㏒e; also ㏑) of 1 + x for the number x. rule log1p { bind x; return (native:fn log1p $x) } -#*Returns the base-10 logarithm of x. +#* Returns the base-10 logarithm of x. rule log10 { bind x; return (native:fn log10 $x) } -#*Returns the base-2 logarithm of x. +#* Returns the base-2 logarithm of x. rule log2 { bind x; return (native:fn log2 $x) } # TODO: support more than 2 arguments, like in the JS native version -#*Returns the largest of x and y numbers. +#* Returns the largest of x and y numbers. rule max { bind x y; return (native:fn max $x $y) } # TODO: support more than 2 arguments, like in the JS native version -#*Returns the smallest of x and y. +#* Returns the smallest of x and y. rule min { bind x y; return (native:fn min $x $y) } -#*Returns base x to the exponent power y (that is, xy). +#* Returns base x to the exponent power y (that is, xy). rule pow { bind x y; return (native:fn pow $x $y) } -#*Returns a pseudo-random number between 0 and 1. +#* Returns a pseudo-random number between 0 and 1. rule random { return (native:fn random) } -#*Returns the value of the number x rounded to the nearest integer. +#* Returns the value of the number x rounded to the nearest integer. rule round { bind x; return (native:fn round $x) } -#*Returns the sign of the x, indicating whether x is positive, negative, or zero. +#* Returns the sign of the x, indicating whether x is positive, negative, or zero. rule sign { bind x; return (native:fn sign $x) } -#*Returns the sine of x. +#* Returns the sine of x. rule sin { bind x; return (native:fn sin $x) } -#*Returns the hyperbolic sine of x. +#* Returns the hyperbolic sine of x. rule sinh { bind x; return (native:fn sinh $x) } -#*Returns the positive square root of x. +#* Returns the positive square root of x. rule sqrt { bind x; return (native:fn sqrt $x) } -#*Returns the tangent of x. +#* Returns the tangent of x. rule tan { bind x; return (native:fn tan $x) } -#*Returns the hyperbolic tangent of x. +#* Returns the hyperbolic tangent of x. rule tanh { bind x; return (native:fn tanh $x) } -#*Returns the integer portion of x, removing any fractional digits. +#* Returns the integer portion of x, removing any fractional digits. rule trunc { bind x; return (native:fn trunc $x) } diff --git a/packages/docs/out/rule.md b/packages/docs/out/rule.md deleted file mode 100644 index 1cff588..0000000 --- a/packages/docs/out/rule.md +++ /dev/null @@ -1,386 +0,0 @@ -> This was generated using BrowseDoc which is still very much a work in progress - -# Table of Contents - -- [Scope: std](#scope-std) - - [`help`](#help) - - [`scope`](#scope) - - [`id value`](#id-value) - - [`get key`](#get-key) - - [`arr_get index array`](#arr_get-index-array) - - [`dict_get key dict`](#dict_get-key-dict) - - [`set key value`](#set-key-value) - - [`arr_set index value array`](#arr_set-index-value-array) - - [`dict_set key value dict`](#dict_set-key-value-dict) - - [`unset key`](#unset-key) - - [`dict_unset key dict`](#dict_unset-key-dict) - - [`update key value`](#update-key-value) - - [`push value dest`](#push-value-dest) - - [`pop dest`](#pop-dest) - - [`rule name body`](#rule-name-body) - - [`sleep ms`](#sleep-ms) - - [`print`](#print) - - [`if condition then thenRuleSet else elseRuleSet`](#if-condition-then-thenRuleSet-else-elseRuleSet) - - [`for iterator body`](#for-iterator-body) - - [`eval ruleset inject`](#eval-ruleset-inject) - - [`arr ruleset`](#arr-ruleset) - - [`dict ruleset`](#dict-ruleset) - - [`import`](#import) - - [`string value`](#string-value) - - [`len value`](#len-value) -- [Scope: rule](#scope-rule) - - [`bind`](#bind) - - [`return value`](#return-value) - -## Scope `std` - -This scope is available to every program and consists of all the core rules to write useful browse programs - -## Rules - -### `help` - -Run `help` in a repl, or add it to your code during debugging, to learn about all the rules you can use in a scope - -### `scope` - -Internal: this dumps the current JS scope to stdout for debugging - -### `id value` - -- `value` \<**T**\> Any value - -- Returns: \<**T**\> The value passed in, unchanged - -Returns whatever value is passed in. This is the _identity_ rule - -### `get key` - -- `key` \<**string**\> An identifer - -- Returns: \<**any**\> The value of `key` - -Resolves to the value of the variable `key` - -> The shorthand for this rule is `$`. So, `$someVar` is the -> same as `(get someVar)`. The shorthand syntax is the preferred way to -> read a value. - -### `arr_get index array` - -- `index` \<**number**\> A valid 0-indexed position in the `array` - -- `array` \<**arr\**\> The array to lookup - -- Returns: \<**T**\> The element at `index` in the `array` - -Get the element at `index` in the `array` - -### `dict_get key dict` - -- `key` \<**K**\> A valid key in the dictionary - -- `dict` \<**dict\**\> The dictionary to lookup - -- Returns: \<**V**\> The value of `key` in the `dict` dictionary - -Get the value of `key` in the `dict` dictionary - -### `set key value` - -- `key` \<**string**\> An identifer (a.k.a variable name) - -- `value` \<**T**\> The value to set the variable to - -- Returns: \<**T**\> value - -sets to the value of the variable `key` to `value` - -> 'set' always creates/updates the variable in the immediate/local scope. -> If a variable with the same name exists in a higher scope, it will be -> 'shadowed', not updated. To update a variable instead of creating a -> new one, use the [update](#update-key-value) rule. - -### `arr_set index value array` - -- `index` \<**number**\> A valid 0-indexed position in the `array` - -- `value` \<**T**\> The value to set in the array - -- `array` \<**arr\**\> The array to write to - -- Returns: \<**T**\> The value - -Set the element at `index` in the `array` to `value` - -> To increase the size of the array, see [push](#push-value-dest) or use the `array` library - -### `dict_set key value dict` - -- `key` \<**K**\> The key in the dictionary to set - -- `value` \<**V**\> The value to set `key` to in the dictionary - -- `dict` \<**dict\**\> The dictionary to write to - -- Returns: \<**V**\> The value - -Set the value of `key` in the `dict` dictionary - -### `unset key` - -- `key` \<**string**\> An identifer - -- Returns: \<**any**\> The value stored in the variable key - -Unset the variable 'key' - -### `dict_unset key dict` - -- `key` \<**K**\> A valid key in dict - -- `dict` \<**dict\**\> The dictionary to update - -- Returns: \<**V**\> The value from the deleted pair - -Delete the key-value record matching `key` from the dictionary `dict` - -### `update key value` - -- `key` \<**string**\> An identifer (a.k.a variable name) - -- `value` \<**V**\> The value to set the variable to - -- Returns: \<**V**\> value - -Updates the variable 'key' to the value 'value' - -> 'update' updates the value for the variable `key` in the closest ancestor scope. -> If a variable with the name `key` already exists in the current scope, then -> `update` throws an error. You should use [set](#set-key-value) instead for such cases. - -### `push value dest` - -- `value` \<**T**\> The value to push - -- `dest` \<**arr\**\> The array to push to - -- Returns: \<**number**\> The number of elements in the array after pushing to it - -Push an element to the back of an array - -### `pop dest` - -- `dest` \<**arr\**\> The array to remove an element from - -- Returns: \<**T**\> The value of the element removed - -Remove the element at the back of the array and return it - -### `rule name body` - -- `name` \<**string**\> An identifer to name the rule - -- `body` \<**RuleSet**\> The behavior that should be executed when rule is called with arguments - -- Returns: \<**Rule**\> TODO: This value cannot be used by browse and is only understood by the runtime. Provide a better value - -Define a new rule 'name'. The 'body' has access to two additional rules, [bind](#bind) and [return](#return-value) used to take arguments and return a value - -### `sleep ms` - -- `ms` \<**number**\> The number of milliseconds to sleep for - -- Returns: \<**number**\> ms - -Sleep for 'ms' milliseconds - -> This is a blocking rule - -### `print` - -- Returns: \<**any**\> The value of the last argument passed to print - -Print values to stdout - -``` -# Hello World -print Hello World - -# Since 'print' evaluates to the last argument passed in, it makes -# it easy to compose `print` when debuggin complicated expressions -rule fact { - bind x - if $x <= 1 then { return $x } else { - return (print $x + '! =' $x * (fact $x - 1)) - } -} -fact 4 - -# output = -# 2! = 2 -# 3! = 6 -# 4! = 24 - -``` - -### `if condition then thenRuleSet else elseRuleSet` - -- `condition` \<**any**\> The condition to test - -- `then` \<**"then"**\> The string "then" - -- `thenRuleSet` \<**RuleSet**\> The ruleset that will be executed if condition evaluates to true - ? -- `else` \<**"else"**\> The string "else" - ? -- `elseRuleSet` \<**RuleSet**\> The ruleset that will be executed if condition evaluates to false - -- Returns: \<**any**\> The result of the RuleSet that was evaluated code. `nil` is no `else` claus is provided - -If 'condition' is truthy, evaluate the 'then' RuleSet, else evaluate the 'else' rule set - -> If `else` and `elseRuleSet` are not provided, then nothing is evaluated if the `condition` -> is falsy. The entire `if` rule will evaluate to `nil` in this case - -``` -if ($grade > 60) then { print pass -``` - -### `for iterator body` - -- `iterator` \<**RuleSet**\> The iteration criteria - -- `body` \<**RuleSet**\> The body of the loop - -- Returns: \<**nil**\> nil (TODO: Should return the value of the last evaluated statement, or the number of iterations?) - -Execute the `body` while the `test` expressions in the `interator` do not fail - -> The contents of the iterator is split into multiple parts: -> -> - The very first rule is evaluated once, at the beginning, to setup the loop. -> Usually used to set a iteration variable -> - The remaining rules, except the last rule, are evaulated at the start of each -> rule. A `test` rule is available here that causes the loop to end if the first -> argument passed to `test` is falsy -> - The last rule is run at the end of each loop, i.e. affter the `body` is evaluated, -> but before the `test` rules (previous point) are evaluated again. Usually use to -> increment the iteration variable defined in point 1 - -``` -for { set i 2; test $i < 5; set i $i + 1 } { print loop $i } -``` - -### `eval ruleset inject` - -- `ruleset` \<**RuleSet**\> The RuleSet to evaluate - ? -- `inject` \<**RuleSet**\> A RuleSet that is evaluated in the scope before the ruleset is evaluated - -- Returns: \<**any**\> The result of evaluating the ruleset - -Evaluate a RuleSet. Optionally, inject variables and additional rules into the evaluation context/scope - -> inject is used to add additional variables and rules that can be used by the Ruleset -> This is the "explicit" form of scope injection that's used to make a pleasant experience -> for someone using a given library. See `examples/advanced/custom_rules.browse` in the browse -> repo to see some good examples for this - -``` -# See https://github.com/windsorio/browse/blob/master/examples/advanced/custom_rules.browse - -``` - -### `arr ruleset` - -- `ruleset` \<**RuleSet**\> The RuleSet used to instantiate the array - -- Returns: \<**arr\**\> The array - -Create an Array from a RuleSet - -> `arr` creates a new array, and then evaluates the RuleSet -> A rule called `el` is available inside this RuleSet. It takes one argument -> Each `el` call adds that element to the array before returning the final -> array. -> -> `e` and `_` are aliases for `el` - -``` -set a1 (arr { _ 1; _ 2; _ 3 }) - -# nested arrays -set a2 (arr { - _ (arr { - _ 1 - }) -}) - -``` - -### `dict ruleset` - -- `ruleset` \<**RuleSet**\> The RuleSet used to instantiate the dictionary - -- Returns: \<**dict\**\> The dictionary - -Create a Dictionary from a RuleSet - -> `dict` creates a new dictionary, and then evaluates the RuleSet -> A rule called `record` is available inside this RuleSet. It takes two arguments, -> a `key` and `value`. Each `record` call adds a new record to the dictionary -> mapping the `key` to the `value`. The final dictionary is `returned`. -> -> `r` and `_` are aliases for `record` - -``` -set o1 (dict { _ k1 v1; _ k2 v2 }) - -# nested dictionaries -set o2 (dict { - _ k1 (dict { - _ k2 v2 - }) -}) - -``` - -### `import` - -Import a module. Read the [Browse Modules](#) guide for more info (TODO) - -### `string value` - -- `value` \<**any**\> Any value - -Serialize any value as a string - -### `len value` - -- `value` \<**string | array\**\> A string or array - -Get the length of the string or number of elements in an array - -## Scope `rule` - -## Rules - -### `bind` - -- Returns: \<**any**\> nil - -'bind' lets the rule accept arguments. Strings passed to bind are used to assign variables that track the incoming values - -``` -# take 2 arguments and return the sum rule add { bind x y; return $x + $y } # accept options rule add2 { bind(print) x y set z $x + $y if $print then { print $z } else { return $z } } -``` - -### `return value` - -- `value` \<**T**\> The value to return -- Returns: \<**T**\> The value passed in, unchanged - -'return' is often used to make the return value for a rule explicit. It's often unnecessary however since every rule uses the last evaluated value in its body as the return value anyway. - -> The return rule doesn't work like `return` in other languages. `return` is just an alias for [id](#id-value) since the last value in a RuleSet is the implicit return value of the RuleSet. For example `rule f { return foo return bar }` In browse, this is valid and the return value is "bar". `return foo` is the same as `id foo` Which basically does nothing (a.k.a it's a no-op). and the last rule in the body evaluates to "bar" diff --git a/packages/docs/out/std.md b/packages/docs/out/std.md index 1cff588..61e223f 100644 --- a/packages/docs/out/std.md +++ b/packages/docs/out/std.md @@ -49,7 +49,6 @@ Internal: this dumps the current JS scope to stdout for debugging ### `id value` - `value` \<**T**\> Any value - - Returns: \<**T**\> The value passed in, unchanged Returns whatever value is passed in. This is the _identity_ rule @@ -57,7 +56,6 @@ Returns whatever value is passed in. This is the _identity_ rule ### `get key` - `key` \<**string**\> An identifer - - Returns: \<**any**\> The value of `key` Resolves to the value of the variable `key` @@ -71,7 +69,6 @@ Resolves to the value of the variable `key` - `index` \<**number**\> A valid 0-indexed position in the `array` - `array` \<**arr\**\> The array to lookup - - Returns: \<**T**\> The element at `index` in the `array` Get the element at `index` in the `array` @@ -81,7 +78,6 @@ Get the element at `index` in the `array` - `key` \<**K**\> A valid key in the dictionary - `dict` \<**dict\**\> The dictionary to lookup - - Returns: \<**V**\> The value of `key` in the `dict` dictionary Get the value of `key` in the `dict` dictionary @@ -91,7 +87,6 @@ Get the value of `key` in the `dict` dictionary - `key` \<**string**\> An identifer (a.k.a variable name) - `value` \<**T**\> The value to set the variable to - - Returns: \<**T**\> value sets to the value of the variable `key` to `value` @@ -99,7 +94,7 @@ sets to the value of the variable `key` to `value` > 'set' always creates/updates the variable in the immediate/local scope. > If a variable with the same name exists in a higher scope, it will be > 'shadowed', not updated. To update a variable instead of creating a -> new one, use the [update](#update-key-value) rule. +> new one, use the [update](#update) rule. ### `arr_set index value array` @@ -108,12 +103,11 @@ sets to the value of the variable `key` to `value` - `value` \<**T**\> The value to set in the array - `array` \<**arr\**\> The array to write to - - Returns: \<**T**\> The value Set the element at `index` in the `array` to `value` -> To increase the size of the array, see [push](#push-value-dest) or use the `array` library +> To increase the size of the array, see [push](#push) or use the `array` library ### `dict_set key value dict` @@ -122,7 +116,6 @@ Set the element at `index` in the `array` to `value` - `value` \<**V**\> The value to set `key` to in the dictionary - `dict` \<**dict\**\> The dictionary to write to - - Returns: \<**V**\> The value Set the value of `key` in the `dict` dictionary @@ -130,7 +123,6 @@ Set the value of `key` in the `dict` dictionary ### `unset key` - `key` \<**string**\> An identifer - - Returns: \<**any**\> The value stored in the variable key Unset the variable 'key' @@ -140,7 +132,6 @@ Unset the variable 'key' - `key` \<**K**\> A valid key in dict - `dict` \<**dict\**\> The dictionary to update - - Returns: \<**V**\> The value from the deleted pair Delete the key-value record matching `key` from the dictionary `dict` @@ -150,21 +141,19 @@ Delete the key-value record matching `key` from the dictionary `dict` - `key` \<**string**\> An identifer (a.k.a variable name) - `value` \<**V**\> The value to set the variable to - - Returns: \<**V**\> value Updates the variable 'key' to the value 'value' > 'update' updates the value for the variable `key` in the closest ancestor scope. > If a variable with the name `key` already exists in the current scope, then -> `update` throws an error. You should use [set](#set-key-value) instead for such cases. +> `update` throws an error. You should use [set](#set) instead for such cases. ### `push value dest` - `value` \<**T**\> The value to push - `dest` \<**arr\**\> The array to push to - - Returns: \<**number**\> The number of elements in the array after pushing to it Push an element to the back of an array @@ -172,7 +161,6 @@ Push an element to the back of an array ### `pop dest` - `dest` \<**arr\**\> The array to remove an element from - - Returns: \<**T**\> The value of the element removed Remove the element at the back of the array and return it @@ -182,15 +170,13 @@ Remove the element at the back of the array and return it - `name` \<**string**\> An identifer to name the rule - `body` \<**RuleSet**\> The behavior that should be executed when rule is called with arguments - - Returns: \<**Rule**\> TODO: This value cannot be used by browse and is only understood by the runtime. Provide a better value -Define a new rule 'name'. The 'body' has access to two additional rules, [bind](#bind) and [return](#return-value) used to take arguments and return a value +Define a new rule 'name'. The 'body' has access to two additional rules, [bind](#bind) and [return](#return) used to take arguments and return a value ### `sleep ms` - `ms` \<**number**\> The number of milliseconds to sleep for - - Returns: \<**number**\> ms Sleep for 'ms' milliseconds @@ -221,7 +207,6 @@ fact 4 # 2! = 2 # 3! = 6 # 4! = 24 - ``` ### `if condition then thenRuleSet else elseRuleSet` @@ -235,7 +220,6 @@ fact 4 - `else` \<**"else"**\> The string "else" ? - `elseRuleSet` \<**RuleSet**\> The ruleset that will be executed if condition evaluates to false - - Returns: \<**any**\> The result of the RuleSet that was evaluated code. `nil` is no `else` claus is provided If 'condition' is truthy, evaluate the 'then' RuleSet, else evaluate the 'else' rule set @@ -252,7 +236,6 @@ if ($grade > 60) then { print pass - `iterator` \<**RuleSet**\> The iteration criteria - `body` \<**RuleSet**\> The body of the loop - - Returns: \<**nil**\> nil (TODO: Should return the value of the last evaluated statement, or the number of iterations?) Execute the `body` while the `test` expressions in the `interator` do not fail @@ -277,7 +260,6 @@ for { set i 2; test $i < 5; set i $i + 1 } { print loop $i } - `ruleset` \<**RuleSet**\> The RuleSet to evaluate ? - `inject` \<**RuleSet**\> A RuleSet that is evaluated in the scope before the ruleset is evaluated - - Returns: \<**any**\> The result of evaluating the ruleset Evaluate a RuleSet. Optionally, inject variables and additional rules into the evaluation context/scope @@ -289,13 +271,11 @@ Evaluate a RuleSet. Optionally, inject variables and additional rules into the e ``` # See https://github.com/windsorio/browse/blob/master/examples/advanced/custom_rules.browse - ``` ### `arr ruleset` - `ruleset` \<**RuleSet**\> The RuleSet used to instantiate the array - - Returns: \<**arr\**\> The array Create an Array from a RuleSet @@ -316,13 +296,11 @@ set a2 (arr { _ 1 }) }) - ``` ### `dict ruleset` - `ruleset` \<**RuleSet**\> The RuleSet used to instantiate the dictionary - - Returns: \<**dict\**\> The dictionary Create a Dictionary from a RuleSet @@ -343,7 +321,6 @@ set o2 (dict { _ k2 v2 }) }) - ``` ### `import` @@ -383,4 +360,4 @@ Get the length of the string or number of elements in an array 'return' is often used to make the return value for a rule explicit. It's often unnecessary however since every rule uses the last evaluated value in its body as the return value anyway. -> The return rule doesn't work like `return` in other languages. `return` is just an alias for [id](#id-value) since the last value in a RuleSet is the implicit return value of the RuleSet. For example `rule f { return foo return bar }` In browse, this is valid and the return value is "bar". `return foo` is the same as `id foo` Which basically does nothing (a.k.a it's a no-op). and the last rule in the body evaluates to "bar" +> The return rule doesn't work like `return` in other languages. `return` is just an alias for [id](#id) since the last value in a RuleSet is the implicit return value of the RuleSet. For example `rule f { return foo return bar }` In browse, this is valid and the return value is "bar". `return foo` is the same as `id foo` Which basically does nothing (a.k.a it's a no-op). and the last rule in the body evaluates to "bar" diff --git a/packages/docs/parsers/common.js b/packages/docs/parsers/common.js index 5259af6..0448ecf 100644 --- a/packages/docs/parsers/common.js +++ b/packages/docs/parsers/common.js @@ -27,7 +27,7 @@ const pullTags = (comment) => { "" ); if (val.endsWith("\n")) val = val.slice(0, -1); - rtn[tag] = val; + rtn[tag] = val.trim(); } return rtn; }; diff --git a/packages/docs/parsers/js.js b/packages/docs/parsers/js.js index 64474a1..c17325c 100644 --- a/packages/docs/parsers/js.js +++ b/packages/docs/parsers/js.js @@ -223,19 +223,40 @@ module.exports = (code, fileName) => { //In the case of a rule definition which has been tagged with a scope else if (tags["@scope"] !== undefined && tags["@rule"] !== undefined) { const scopeName = (tags["@scope"] || scope || fileName).trim(); - - if (!rtn[scopeName]) { - console.warn( - `WARNING:: Scope ${scopeName} does not exist. Creating new scope definition.` - ); - rtn[scopeName] = {}; + let scopeObj = rtn; + //In the case that this scope doesn't exist, we check for an @parent tag. If that doesn't exist we create a new scope + if (!scopeObj[scopeName]) { + //TODO: inference parent + if (tags["@parent"]) { + //TODO: Support arbitrarily nested scopes (currently supports one level of nesting) + //If the parent exists We create a child scope + if (!scopeObj[tags["@parent"]]) { + console.warn( + `WARNING:: Parent Scope '${ + scopeObj[tags["@parent"]] + }' for scope ${scopeName} does not exist. Creating new scope definition.` + ); + scopeObj[tags["@parent"]] = {}; + } + if (!scopeObj[tags["@parent"]]["children"]) { + scopeObj[tags["@parent"]]["children"] = {}; + } + scopeObj = scopeObj[tags["@parent"]]["children"]; + //Since this is a child scope, we don't need to print a warning + if (!scopeObj[scopeName]) scopeObj[scopeName] = {}; + } else { + console.warn( + `WARNING:: Scope '${scopeName}' does not exist. Creating new scope definition.` + ); + scopeObj[scopeName] = {}; + } } /* Deal with the Rule annotations */ //Rules - if (!rtn[scopeName]["rules"]) rtn[scopeName]["rules"] = {}; + if (!scopeObj[scopeName]["rules"]) scopeObj[scopeName]["rules"] = {}; - rtn[scopeName]["rules"][tags["@rule"]] = processRule( + scopeObj[scopeName]["rules"][tags["@rule"]] = processRule( path.node.leadingComments.map((comment) => ({ ...comment, value: cleanComment(comment.value), diff --git a/packages/docs/plugins/markdownGen.js b/packages/docs/plugins/markdownGen.js index 0b701ba..6be78ec 100644 --- a/packages/docs/plugins/markdownGen.js +++ b/packages/docs/plugins/markdownGen.js @@ -26,21 +26,21 @@ const subLinks = (str, map) => link(rule.trim(), `#${map[rule.trim()] || rule.trim()}`) ); -module.exports = async (docTree, file) => { - const readmeLines = [ - quote( - "This was generated using BrowseDoc which is still very much a work in progress" - ), - line, - h1("Table of Contents"), - line, - ]; +const startingLines = [ + quote( + "This was generated using BrowseDoc which is still very much a work in progress" + ), + line, + h1("Table of Contents"), + line, +]; + +const getDirectory = (docTree) => { + const readmeLines = []; // mapping of a rulename to a link slug const ruleMap = {}; - const varMap = {}; - //Build Documentation Directory (Inspired by https://nodejs.org/api/fs.html) readmeLines.push( bullet( @@ -76,7 +76,20 @@ module.exports = async (docTree, file) => { }) ) ); + const childrenLines = Object.keys(docTree) + .map((scope) => { + if (docTree[scope]["children"]) { + return getDirectory(docTree[scope]["children"]); + } + }) + .filter(Boolean); + return [...readmeLines, ...childrenLines]; +}; +const getReadme = (docTree, file, directory = null) => { + const ruleMap = {}; + const varMap = {}; + const readmeLines = []; //Build actual documentation Object.keys(docTree).map((scope) => { readmeLines.push(line); @@ -153,10 +166,25 @@ module.exports = async (docTree, file) => { }); readmeLines.push(bullet(configLines)); } + + //Also write the children readme's below this one + //TODO: Could indent, or have some special rendering for parents + const childrenLines = docTree[scope]["children"] + ? getReadme(docTree[scope]["children"], file) + : []; + readmeLines.push(...childrenLines); }); + return readmeLines; +}; + +module.exports = async (docTree, file) => { + const directory = getDirectory(docTree); + const readmeContents = getReadme(docTree, file); if (typeof file === "string") { - await fs.promises.writeFile(file, readmeLines.join("\n")); + await fs.promises.writeFile( + file, + [...startingLines, ...directory, ...readmeContents].join("\n") + ); } - return readmeLines.join("\n"); };