diff --git a/common/markdown_parser/parse-expression.js b/common/markdown_parser/parse-expression.js index 034657a1..609ac4b9 100644 --- a/common/markdown_parser/parse-expression.js +++ b/common/markdown_parser/parse-expression.js @@ -3,16 +3,16 @@ import {LRParser} from "@lezer/lr" const spec_Identifier = {__proto__:null,null:22, and:36, or:38, where:48, limit:52, select:66, as:70, render:74, each:76, all:78} export const parser = LRParser.deserialize({ version: 14, - states: ",fOYQPOOOOQO'#Cc'#CcO!ZQPO'#ChOOQO'#C`'#C`Q!bQQOOOOQO'#Ck'#CkOYQPO'#ClO#lQSO'#D]OYQPO'#DVO%XQQO'#C_OOQO'#C_'#C_O&RQQO'#DhO&`QPO,59SOOQO,59S,59SO&eQPO,59UOYQPO,59sOYQPO,59sOYQPO,59sOYQPO,59uOYQPO,59XOYQPO,59XO&jQQO,59WO'SQPO'#CqO'ZQPO,59[O'`QPO'#D^O'eQPO'#ESO'mQPO,59wOOQO,59w,59wO'rQQO,59qO)uQPO,59vOYQPO'#D_O)|QPO,5:SOOQO1G.n1G.nOOQO1G.p1G.pO,UQQO1G/_O.YQQO1G/_O.gQQO1G/_O.qQQO1G/aO0xQQO1G.sO1PQQO1G.sOOQO1G.r1G.rOYQPO'#CwOOQO'#D`'#D`O1WQPO,59]OYQPO'#CsOYQPO'#CuO1_QPO'#C|O2`QPO'#DQOOQO1G.v1G.vOYQPO,59xO2kQPO'#DcO2pQPO,5:nOOQO1G/c1G/cO2xQPO1G/bOOQO1G/b1G/bO2}QQO,59yOOQO-E7]-E7]OYQPO7+${O3[QQO'#CyO3xQPO'#DoOOQO,59c,59cOOQO-E7^-E7^O4aQQO,59_O4wQQO,59aO5_QQO'#DOO5fQQO'#DOO6PQPO'#DpOOQO,59h,59hOOQO,59l,59lO6hQPO,59lO6mQQO1G/dOOQO,59},59}OOQO-E7a-E7aOOQO7+$|7+$|O6wQQO< spec_Identifier[value] || -1}], - tokenPrec: 1151 + tokenPrec: 1274 }) diff --git a/common/markdown_parser/parse-query.js b/common/markdown_parser/parse-query.js index 5b3c7ae3..e605e82e 100644 --- a/common/markdown_parser/parse-query.js +++ b/common/markdown_parser/parse-query.js @@ -3,16 +3,16 @@ import {LRParser} from "@lezer/lr" const spec_Identifier = {__proto__:null,where:14, null:30, and:44, or:46, limit:70, select:84, as:88, render:92, each:94, all:96} export const parser = LRParser.deserialize({ version: 14, - states: ",fOYQPOOOpQQO'#C_QOQPOOOzQQO'#DQOOQO'#D_'#D_O!{QQO,58yOzQQO'#CaOzQQO'#DOO#VQQO'#DVO$WQQO'#DZOOQO'#Ch'#ChO$cQQO'#ClOOQO'#Ce'#CeO%tQSO'#DSOOQO'#Co'#CoOzQQO'#CpO&eQPO'#C|OzQQO'#CuO(QQSO'#CdOOQO'#Cd'#CdO(zQQO'#EROOQO,59l,59lOOQO-E7]-E7]O)fQSO,58{O*PQSO,59jO*jQSO'#DXO*qQSO'#CdO+_QQO'#ESOOQO,59q,59qOOQO,59u,59uO+yQPO,59uO,OQSO'#DhO,]QPO,59WOOQO,59W,59WO,bQQO,59YOzQQO,59cOzQQO,59cOzQQO,59cOzQQO,59eOOQO'#DT'#DTOOQO,59n,59nOzQQO,59]OzQQO,59]O,gQSO,59[O,nQPO,59`O,sQPO'#C}O,xQPO'#EQO-QQPO,59hOOQO,59h,59hO-VQSO,59aO/YQQO,59fOzQQO'#DbO/aQQO,5:mO/{QQO,59sO#VQQO'#DcO0QQQO,5:nOOQO1G/a1G/aOzQQO'#D`O0lQPO,5:SOOQO1G.r1G.rOOQO1G.t1G.tO2tQSO1G.}O4xQSO1G.}O5VQSO1G.}O5aQSO1G/PO7hQSO1G.wO7oQSO1G.wOOQO1G.v1G.vOOQO1G.z1G.zOzQQO,59iO7vQPO'#DaO7{QPO,5:lOOQO1G/S1G/SO8TQPO1G/QOOQO1G/Q1G/QOOQO,59|,59|OOQO-E7`-E7`OOQO1G/_1G/_OOQO,59},59}OOQO-E7a-E7aO8YQSO,59zOOQO-E7^-E7^OzQQO7+$kO8gQSO1G/TOOQO,59{,59{OOQO-E7_-E7_OOQO7+$l7+$lO8qQSO< spec_Identifier[value] || -1}], - tokenPrec: 1186 + tokenPrec: 1309 }) diff --git a/common/markdown_parser/query.grammar b/common/markdown_parser/query.grammar index d88bf653..6f7f7efb 100644 --- a/common/markdown_parser/query.grammar +++ b/common/markdown_parser/query.grammar @@ -99,6 +99,8 @@ BinExpression { | Expression !mulop "%" Expression | Expression !addop "+" Expression | Expression !addop "-" Expression + +| Expression !or "??" Expression } TernaryExpression { diff --git a/common/template/template_parser.test.ts b/common/template/template_parser.test.ts index 3462bb9c..4669aa54 100644 --- a/common/template/template_parser.test.ts +++ b/common/template/template_parser.test.ts @@ -18,7 +18,7 @@ Deno.test("Test template", () => { ]], "}"]], ]]]); - assertEquals(parseTemplate(`{{escapeRegexp @page.name}}`), ["Template", [ + assertEquals(parseTemplate(`{{escapeRegexp(@page.name)}}`), ["Template", [ "TemplateElement", ["ExpressionDirective", ["Expression", [ "Call", diff --git a/common/template/template_parser.ts b/common/template/template_parser.ts index 36e4a9d9..458a3acc 100644 --- a/common/template/template_parser.ts +++ b/common/template/template_parser.ts @@ -41,17 +41,8 @@ function processTree(tree: AST): AST { case "TemplateElement": return ["TemplateElement", ...(tree.slice(1) as AST[]).map(processTree)]; case "ExpressionDirective": { - let exprString = tree[2][1] as string; - const legacyCallSyntax = /^([A-Za-z]+)\s+([^(]+$)/.exec(exprString); - if (legacyCallSyntax) { - // Translates "escapeRegex @page.name" -> "escapeRegex(@page.name)" - const [_, fn, args] = legacyCallSyntax; - exprString = `${fn}(${args})`; - console.warn( - "Translated legacy function call to new syntax", - exprString, - ); - } + const exprString = tree[2][1] as string; + const expressionTree = parseTreeToAST(parse( expressionLanguage, exprString, diff --git a/plug-api/lib/query_expression.ts b/plug-api/lib/query_expression.ts index 8a54c7e4..2fced298 100644 --- a/plug-api/lib/query_expression.ts +++ b/plug-api/lib/query_expression.ts @@ -25,7 +25,7 @@ export function evalQueryExpression( } else if (op1Val) { return evalQueryExpression(val[2], obj, variables, functionMap); } else { - return false; + return op1Val; } } case "or": { @@ -41,7 +41,7 @@ export function evalQueryExpression( evalQueryExpression(val[2], obj, variables, functionMap) ); } else if (op1Val) { - return true; + return op1Val; } else { return evalQueryExpression(val[2], obj, variables, functionMap); } @@ -274,6 +274,8 @@ function evalSimpleExpression(type: string, val1: any, val2: any, val3: any) { return val2.includes(val1); case "?": return val1 ? val2 : val3; + case "??": + return val1 ?? val2; default: throw new Error(`Unupported operator: ${type}`); } diff --git a/website/Expression Language.md b/website/Expression Language.md index 8c681f54..28314c08 100644 --- a/website/Expression Language.md +++ b/website/Expression Language.md @@ -28,10 +28,11 @@ Attribute of variable: {{@page.name}} # Function calls * `functionName(argument1, argument2, ...)`: call function `functionName` -* `functionName`: call `functionName` without any arguments +* `functionName()` or `functionName`: call function `functionName` without arguments ## Examples ```template +contains with argument list: {{contains("FizzBuzz", "Fizz")}} Today with argument list: {{today()}} Today without an argument list: {{today}} ``` diff --git a/website/Library/Core.md b/website/Library/Core.md index 6b3ef427..0b847daf 100644 --- a/website/Library/Core.md +++ b/website/Library/Core.md @@ -13,13 +13,13 @@ To import this library, run the {[Library: Import]} command in your SilverBullet # Included templates ```query template -where name =~ /^{{escapeRegexp @page.name}}\// +where name =~ /^{{escapeRegexp(@page.name)}}\// render [[Library/Core/Query/Template]] ``` # Included utility pages ```query page -where name =~ /^{{escapeRegexp @page.name}}\// and tags != "template" +where name =~ /^{{escapeRegexp(@page.name)}}\// and tags != "template" render [[Library/Core/Query/Page]] ``` diff --git a/website/Library/Journal.md b/website/Library/Journal.md index f10fa23c..b2c0ed1b 100644 --- a/website/Library/Journal.md +++ b/website/Library/Journal.md @@ -8,7 +8,7 @@ To import this library, run the {[Library: Import]} command in your SilverBullet # Included templates ```query page -where name =~ /^{{escapeRegexp @page.name}}\// +where name =~ /^{{escapeRegexp(@page.name)}}\// render [[Library/Core/Query/Page]] ```