diff --git a/demo/kitchen-sink/docs/prql.prql b/demo/kitchen-sink/docs/prql.prql new file mode 100644 index 00000000000..5387d697b6f --- /dev/null +++ b/demo/kitchen-sink/docs/prql.prql @@ -0,0 +1,22 @@ +from invoices +filter invoice_date >= @1970-01-16 +derive { + transaction_fees = 0.8, + income = total - transaction_fees +} +filter income > 1 +group customer_id ( + aggregate { + average total, + sum_income = sum income, + ct = count total, + } +) +sort {-sum_income} +take 10 +join c=customers (==customer_id) +derive name = f"{c.last_name}, {c.first_name}" +select { + c.customer_id, name, sum_income +} +derive db_version = s"version()" diff --git a/src/ext/modelist.js b/src/ext/modelist.js index 95540ad5404..26617f81d49 100644 --- a/src/ext/modelist.js +++ b/src/ext/modelist.js @@ -170,6 +170,7 @@ var supportedModes = { Prolog: ["plg|prolog"], Properties: ["properties"], Protobuf: ["proto"], + PRQL: ["prql"], Puppet: ["epp|pp"], Python: ["py"], QML: ["qml"], diff --git a/src/mode/prql.js b/src/mode/prql.js new file mode 100644 index 00000000000..2de2433676c --- /dev/null +++ b/src/mode/prql.js @@ -0,0 +1,21 @@ +"use strict"; + +var oop = require("../lib/oop"); +var TextMode = require("./text").Mode; +var HighlightRules = require("./prql_highlight_rules").PrqlHighlightRules; +var FoldMode = require("./folding/cstyle").FoldMode; + +var Mode = function() { + this.HighlightRules = HighlightRules; + this.foldingRules = new FoldMode(); + this.$behaviour = this.$defaultBehaviour; +}; +oop.inherits(Mode, TextMode); + +(function() { + this.lineCommentStart = "#"; + // Extra logic goes here. + this.$id = "ace/mode/prql"; +}).call(Mode.prototype); + +exports.Mode = Mode; diff --git a/src/mode/prql_highlight_rules.js b/src/mode/prql_highlight_rules.js new file mode 100644 index 00000000000..fb9df57dc10 --- /dev/null +++ b/src/mode/prql_highlight_rules.js @@ -0,0 +1,117 @@ +// https://prql-lang.org/ +// https://github.com/PRQL/prql + +"use strict"; + +var oop = require("../lib/oop"); +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var PrqlHighlightRules = function() { + var builtinFunctions = "min|max|sum|average|stddev|every|any|concat_array|count|" + + "lag|lead|first|last|rank|rank_dense|row_number|" + + "round|as|in|" + + "tuple_every|tuple_map|tuple_zip|_eq|_is_null|" + + "from_text|" + + "lower|upper|" + + "read_parquet|read_csv"; + + var builtinTypes = [ + "bool", + "int", + "int8", + "int16", + "int32", + "int64", + "float", + "text", + "set"].join("|"); + + var keywordMapper = this.createKeywordMapper({ + "constant.language": "null", + "constant.language.boolean": "true|false", + "keyword": "let|into|case|prql|type|module|internal", + "storage.type": "let|func", + "support.function": builtinFunctions, + "support.type": builtinTypes + }, "identifier"); + + var escapeRe = /\\(\d+|['"\\&bfnrt]|u[0-9a-fA-F]{4})/; + var identifierRe = /[A-Za-z_][a-z_A-Z0-9]/.source; + var bidi = "[\\u202A\\u202B\\u202D\\u202E\\u2066\\u2067\\u2068\\u202C\\u2069]"; + + this.$rules = { + start: [{ + token: "string.start", + regex: '"', + next: "string" + }, { + token: "string.character", + regex: "'(?:" + escapeRe.source + "|.)'?" + }, { + token : "constant.language", + regex : "^" + identifierRe + "*" + }, { + token : "constant.numeric", // hexadecimal, octal and binary + regex : /0(?:[xX][0-9a-fA-F]+|[oO][0-7]+|[bB][01]+)\b/ + }, { + token : "constant.numeric", // decimal integers and floats + regex : /(?:\d\d*(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+\b)?/ + }, { + token: "comment.block", + regex: "#!.*" + }, { + token: "comment.line", + regex: "#.*" + }, { + token : "keyword.operator", + regex : /->|=>|==|!=|>=|<=|~=|&&|\|\||\?\?|\/\/|@/ + }, { + token: "invalid.illegal", + regex: bidi + }, { + token : "punctuation.operator", + regex : /[,`]/ + }, { + token : keywordMapper, + regex : "[\\w\\xff-\\u218e\\u2455-\\uffff]+\\b" + }, { + token: "paren.lparen", + regex: /[\[({]/ + }, { + token: "paren.rparen", + regex: /[\])}]/ + } ], + string: [{ + token: "constant.character.escape", + regex: escapeRe + }, { + token: "text", + regex: /\\(\s|$)/, + next: "stringGap" + }, { + token: "string.end", + regex: '"', + next: "start" + }, { + token: "invalid.illegal", + regex: bidi + }, { + defaultToken: "string" + }], + stringGap: [{ + token: "text", + regex: /\\/, + next: "string" + }, { + token: "error", + regex: "", + next: "start" + }] + }; + + this.normalizeRules(); +}; + +oop.inherits(PrqlHighlightRules, TextHighlightRules); + +exports.PrqlHighlightRules = PrqlHighlightRules;