From 088ec3f8679fa6f849d54de06eca2e03f6a5183f Mon Sep 17 00:00:00 2001 From: Araozu Date: Thu, 30 May 2024 20:03:54 -0500 Subject: [PATCH] Add docs for lang spec --- public/js/alpine-3.14.0.min.js | 1 + src/components/Navbar.astro | 4 +- src/layouts/BaseLayout.astro | 2 +- src/layouts/DocsLayout.astro | 18 +++ src/layouts/PagesLayout.astro | 12 +- src/layouts/SpecLayout.astro | 18 +++ src/pages/learn/basics/comments.md | 2 +- src/pages/learn/basics/datatypes.md | 2 +- src/pages/learn/basics/hello-world.mdx | 2 +- src/pages/learn/basics/operators.md | 2 +- src/pages/learn/basics/variables.md | 2 +- src/pages/learn/classes/anonymous.md | 2 +- src/pages/learn/classes/definition.md | 2 +- src/pages/learn/classes/interfaces.md | 2 +- src/pages/learn/classes/magic.md | 2 +- src/pages/learn/classes/static.md | 2 +- src/pages/learn/data-structures/arrays.md | 2 +- src/pages/learn/data-structures/enums.md | 2 +- src/pages/learn/data-structures/maps.md | 2 +- src/pages/learn/data-structures/tuples.md | 2 +- src/pages/learn/error-handling/null.md | 2 +- src/pages/learn/error-handling/try.mdx | 2 +- src/pages/learn/flow-control/blocks.md | 2 +- src/pages/learn/flow-control/conditionals.md | 2 +- src/pages/learn/flow-control/loops.md | 2 +- src/pages/learn/flow-control/match.md | 2 +- src/pages/learn/functions/declaration.md | 2 +- src/pages/learn/functions/higher-order.md | 2 +- src/pages/learn/functions/lambdas.md | 2 +- src/pages/learn/functions/parameters.md | 2 +- src/pages/learn/index.mdx | 2 +- src/pages/learn/install.md | 2 +- src/pages/spec/ast/ast.md | 36 ++++++ src/pages/spec/index.md | 129 +++++++++++++++++++ src/pages/spec/tokens/comments.md | 16 +++ src/pages/spec/tokens/grouping.md | 17 +++ src/pages/spec/tokens/identifier.md | 54 ++++++++ src/pages/spec/tokens/newline.md | 15 +++ src/pages/spec/tokens/numbers.md | 56 ++++++++ src/pages/spec/tokens/operator.md | 30 +++++ src/pages/spec/tokens/string.md | 29 +++++ src/pages/spec/tokens/tokens.md | 38 ++++++ 42 files changed, 490 insertions(+), 37 deletions(-) create mode 100644 public/js/alpine-3.14.0.min.js create mode 100644 src/layouts/DocsLayout.astro create mode 100644 src/layouts/SpecLayout.astro create mode 100644 src/pages/spec/ast/ast.md create mode 100644 src/pages/spec/index.md create mode 100644 src/pages/spec/tokens/comments.md create mode 100644 src/pages/spec/tokens/grouping.md create mode 100644 src/pages/spec/tokens/identifier.md create mode 100644 src/pages/spec/tokens/newline.md create mode 100644 src/pages/spec/tokens/numbers.md create mode 100644 src/pages/spec/tokens/operator.md create mode 100644 src/pages/spec/tokens/string.md create mode 100644 src/pages/spec/tokens/tokens.md diff --git a/public/js/alpine-3.14.0.min.js b/public/js/alpine-3.14.0.min.js new file mode 100644 index 0000000..eb0db48 --- /dev/null +++ b/public/js/alpine-3.14.0.min.js @@ -0,0 +1 @@ +(()=>{var rt=!1,nt=!1,U=[],it=-1;function qt(e){Cn(e)}function Cn(e){U.includes(e)||U.push(e),Tn()}function Ee(e){let t=U.indexOf(e);t!==-1&&t>it&&U.splice(t,1)}function Tn(){!nt&&!rt&&(rt=!0,queueMicrotask(Rn))}function Rn(){rt=!1,nt=!0;for(let e=0;ee.effect(t,{scheduler:r=>{ot?qt(r):r()}}),st=e.raw}function at(e){D=e}function Gt(e){let t=()=>{};return[n=>{let i=D(n);return e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach(o=>o())}),e._x_effects.add(i),t=()=>{i!==void 0&&(e._x_effects.delete(i),L(i))},i},()=>{t()}]}function ve(e,t){let r=!0,n,i=D(()=>{let o=e();JSON.stringify(o),r?n=o:queueMicrotask(()=>{t(o,n),n=o}),r=!1});return()=>L(i)}var Jt=[],Yt=[],Xt=[];function Zt(e){Xt.push(e)}function ee(e,t){typeof t=="function"?(e._x_cleanups||(e._x_cleanups=[]),e._x_cleanups.push(t)):(t=e,Yt.push(t))}function Ae(e){Jt.push(e)}function Oe(e,t,r){e._x_attributeCleanups||(e._x_attributeCleanups={}),e._x_attributeCleanups[t]||(e._x_attributeCleanups[t]=[]),e._x_attributeCleanups[t].push(r)}function ct(e,t){e._x_attributeCleanups&&Object.entries(e._x_attributeCleanups).forEach(([r,n])=>{(t===void 0||t.includes(r))&&(n.forEach(i=>i()),delete e._x_attributeCleanups[r])})}function Qt(e){if(e._x_cleanups)for(;e._x_cleanups.length;)e._x_cleanups.pop()()}var lt=new MutationObserver(pt),ut=!1;function le(){lt.observe(document,{subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0}),ut=!0}function ft(){Mn(),lt.disconnect(),ut=!1}var ce=[];function Mn(){let e=lt.takeRecords();ce.push(()=>e.length>0&&pt(e));let t=ce.length;queueMicrotask(()=>{if(ce.length===t)for(;ce.length>0;)ce.shift()()})}function _(e){if(!ut)return e();ft();let t=e();return le(),t}var dt=!1,Se=[];function er(){dt=!0}function tr(){dt=!1,pt(Se),Se=[]}function pt(e){if(dt){Se=Se.concat(e);return}let t=new Set,r=new Set,n=new Map,i=new Map;for(let o=0;os.nodeType===1&&t.add(s)),e[o].removedNodes.forEach(s=>s.nodeType===1&&r.add(s))),e[o].type==="attributes")){let s=e[o].target,a=e[o].attributeName,c=e[o].oldValue,l=()=>{n.has(s)||n.set(s,[]),n.get(s).push({name:a,value:s.getAttribute(a)})},u=()=>{i.has(s)||i.set(s,[]),i.get(s).push(a)};s.hasAttribute(a)&&c===null?l():s.hasAttribute(a)?(u(),l()):u()}i.forEach((o,s)=>{ct(s,o)}),n.forEach((o,s)=>{Jt.forEach(a=>a(s,o))});for(let o of r)t.has(o)||Yt.forEach(s=>s(o));t.forEach(o=>{o._x_ignoreSelf=!0,o._x_ignore=!0});for(let o of t)r.has(o)||o.isConnected&&(delete o._x_ignoreSelf,delete o._x_ignore,Xt.forEach(s=>s(o)),o._x_ignore=!0,o._x_ignoreSelf=!0);t.forEach(o=>{delete o._x_ignoreSelf,delete o._x_ignore}),t=null,r=null,n=null,i=null}function Ce(e){return F(j(e))}function P(e,t,r){return e._x_dataStack=[t,...j(r||e)],()=>{e._x_dataStack=e._x_dataStack.filter(n=>n!==t)}}function j(e){return e._x_dataStack?e._x_dataStack:typeof ShadowRoot=="function"&&e instanceof ShadowRoot?j(e.host):e.parentNode?j(e.parentNode):[]}function F(e){return new Proxy({objects:e},Nn)}var Nn={ownKeys({objects:e}){return Array.from(new Set(e.flatMap(t=>Object.keys(t))))},has({objects:e},t){return t==Symbol.unscopables?!1:e.some(r=>Object.prototype.hasOwnProperty.call(r,t)||Reflect.has(r,t))},get({objects:e},t,r){return t=="toJSON"?Dn:Reflect.get(e.find(n=>Reflect.has(n,t))||{},t,r)},set({objects:e},t,r,n){let i=e.find(s=>Object.prototype.hasOwnProperty.call(s,t))||e[e.length-1],o=Object.getOwnPropertyDescriptor(i,t);return o?.set&&o?.get?Reflect.set(i,t,r,n):Reflect.set(i,t,r)}};function Dn(){return Reflect.ownKeys(this).reduce((t,r)=>(t[r]=Reflect.get(this,r),t),{})}function Te(e){let t=n=>typeof n=="object"&&!Array.isArray(n)&&n!==null,r=(n,i="")=>{Object.entries(Object.getOwnPropertyDescriptors(n)).forEach(([o,{value:s,enumerable:a}])=>{if(a===!1||s===void 0||typeof s=="object"&&s!==null&&s.__v_skip)return;let c=i===""?o:`${i}.${o}`;typeof s=="object"&&s!==null&&s._x_interceptor?n[o]=s.initialize(e,c,o):t(s)&&s!==n&&!(s instanceof Element)&&r(s,c)})};return r(e)}function Re(e,t=()=>{}){let r={initialValue:void 0,_x_interceptor:!0,initialize(n,i,o){return e(this.initialValue,()=>Pn(n,i),s=>mt(n,i,s),i,o)}};return t(r),n=>{if(typeof n=="object"&&n!==null&&n._x_interceptor){let i=r.initialize.bind(r);r.initialize=(o,s,a)=>{let c=n.initialize(o,s,a);return r.initialValue=c,i(o,s,a)}}else r.initialValue=n;return r}}function Pn(e,t){return t.split(".").reduce((r,n)=>r[n],e)}function mt(e,t,r){if(typeof t=="string"&&(t=t.split(".")),t.length===1)e[t[0]]=r;else{if(t.length===0)throw error;return e[t[0]]||(e[t[0]]={}),mt(e[t[0]],t.slice(1),r)}}var rr={};function y(e,t){rr[e]=t}function ue(e,t){return Object.entries(rr).forEach(([r,n])=>{let i=null;function o(){if(i)return i;{let[s,a]=_t(t);return i={interceptor:Re,...s},ee(t,a),i}}Object.defineProperty(e,`$${r}`,{get(){return n(t,o())},enumerable:!1})}),e}function nr(e,t,r,...n){try{return r(...n)}catch(i){te(i,e,t)}}function te(e,t,r=void 0){e=Object.assign(e??{message:"No error message given."},{el:t,expression:r}),console.warn(`Alpine Expression Error: ${e.message}${r?'Expression: "'+r+`"`:""}`,t),setTimeout(()=>{throw e},0)}var Me=!0;function De(e){let t=Me;Me=!1;let r=e();return Me=t,r}function M(e,t,r={}){let n;return x(e,t)(i=>n=i,r),n}function x(...e){return ir(...e)}var ir=gt;function or(e){ir=e}function gt(e,t){let r={};ue(r,e);let n=[r,...j(e)],i=typeof t=="function"?In(n,t):Ln(n,t,e);return nr.bind(null,e,t,i)}function In(e,t){return(r=()=>{},{scope:n={},params:i=[]}={})=>{let o=t.apply(F([n,...e]),i);Ne(r,o)}}var ht={};function kn(e,t){if(ht[e])return ht[e];let r=Object.getPrototypeOf(async function(){}).constructor,n=/^[\n\s]*if.*\(.*\)/.test(e.trim())||/^(let|const)\s/.test(e.trim())?`(async()=>{ ${e} })()`:e,o=(()=>{try{let s=new r(["__self","scope"],`with (scope) { __self.result = ${n} }; __self.finished = true; return __self.result;`);return Object.defineProperty(s,"name",{value:`[Alpine] ${e}`}),s}catch(s){return te(s,t,e),Promise.resolve()}})();return ht[e]=o,o}function Ln(e,t,r){let n=kn(t,r);return(i=()=>{},{scope:o={},params:s=[]}={})=>{n.result=void 0,n.finished=!1;let a=F([o,...e]);if(typeof n=="function"){let c=n(n,a).catch(l=>te(l,r,t));n.finished?(Ne(i,n.result,a,s,r),n.result=void 0):c.then(l=>{Ne(i,l,a,s,r)}).catch(l=>te(l,r,t)).finally(()=>n.result=void 0)}}}function Ne(e,t,r,n,i){if(Me&&typeof t=="function"){let o=t.apply(r,n);o instanceof Promise?o.then(s=>Ne(e,s,r,n)).catch(s=>te(s,i,t)):e(o)}else typeof t=="object"&&t instanceof Promise?t.then(o=>e(o)):e(t)}var bt="x-";function C(e=""){return bt+e}function sr(e){bt=e}var Pe={};function d(e,t){return Pe[e]=t,{before(r){if(!Pe[r]){console.warn(String.raw`Cannot find directive \`${r}\`. \`${e}\` will use the default order of execution`);return}let n=W.indexOf(r);W.splice(n>=0?n:W.indexOf("DEFAULT"),0,e)}}}function ar(e){return Object.keys(Pe).includes(e)}function de(e,t,r){if(t=Array.from(t),e._x_virtualDirectives){let o=Object.entries(e._x_virtualDirectives).map(([a,c])=>({name:a,value:c})),s=wt(o);o=o.map(a=>s.find(c=>c.name===a.name)?{name:`x-bind:${a.name}`,value:`"${a.value}"`}:a),t=t.concat(o)}let n={};return t.map(ur((o,s)=>n[o]=s)).filter(dr).map(jn(n,r)).sort(Fn).map(o=>$n(e,o))}function wt(e){return Array.from(e).map(ur()).filter(t=>!dr(t))}var xt=!1,fe=new Map,cr=Symbol();function lr(e){xt=!0;let t=Symbol();cr=t,fe.set(t,[]);let r=()=>{for(;fe.get(t).length;)fe.get(t).shift()();fe.delete(t)},n=()=>{xt=!1,r()};e(r),n()}function _t(e){let t=[],r=a=>t.push(a),[n,i]=Gt(e);return t.push(i),[{Alpine:B,effect:n,cleanup:r,evaluateLater:x.bind(x,e),evaluate:M.bind(M,e)},()=>t.forEach(a=>a())]}function $n(e,t){let r=()=>{},n=Pe[t.type]||r,[i,o]=_t(e);Oe(e,t.original,o);let s=()=>{e._x_ignore||e._x_ignoreSelf||(n.inline&&n.inline(e,t,i),n=n.bind(n,e,t,i),xt?fe.get(cr).push(n):n())};return s.runCleanups=o,s}var Ie=(e,t)=>({name:r,value:n})=>(r.startsWith(e)&&(r=r.replace(e,t)),{name:r,value:n}),ke=e=>e;function ur(e=()=>{}){return({name:t,value:r})=>{let{name:n,value:i}=fr.reduce((o,s)=>s(o),{name:t,value:r});return n!==t&&e(n,t),{name:n,value:i}}}var fr=[];function re(e){fr.push(e)}function dr({name:e}){return pr().test(e)}var pr=()=>new RegExp(`^${bt}([^:^.]+)\\b`);function jn(e,t){return({name:r,value:n})=>{let i=r.match(pr()),o=r.match(/:([a-zA-Z0-9\-_:]+)/),s=r.match(/\.[^.\]]+(?=[^\]]*$)/g)||[],a=t||e[r]||r;return{type:i?i[1]:null,value:o?o[1]:null,modifiers:s.map(c=>c.replace(".","")),expression:n,original:a}}}var yt="DEFAULT",W=["ignore","ref","data","id","anchor","bind","init","for","model","modelable","transition","show","if",yt,"teleport"];function Fn(e,t){let r=W.indexOf(e.type)===-1?yt:e.type,n=W.indexOf(t.type)===-1?yt:t.type;return W.indexOf(r)-W.indexOf(n)}function G(e,t,r={}){e.dispatchEvent(new CustomEvent(t,{detail:r,bubbles:!0,composed:!0,cancelable:!0}))}function T(e,t){if(typeof ShadowRoot=="function"&&e instanceof ShadowRoot){Array.from(e.children).forEach(i=>T(i,t));return}let r=!1;if(t(e,()=>r=!0),r)return;let n=e.firstElementChild;for(;n;)T(n,t,!1),n=n.nextElementSibling}function E(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}var mr=!1;function _r(){mr&&E("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."),mr=!0,document.body||E("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's ` + diff --git a/src/layouts/DocsLayout.astro b/src/layouts/DocsLayout.astro new file mode 100644 index 0000000..1de543e --- /dev/null +++ b/src/layouts/DocsLayout.astro @@ -0,0 +1,18 @@ +--- +import PagesLayout from "./PagesLayout.astro"; + +const { frontmatter, headings } = Astro.props; + +const posts = await Astro.glob("../pages/learn/**/*.{md,mdx}"); +const indexSubpath = `/learn/index.mdx`; +--- + + + + diff --git a/src/layouts/PagesLayout.astro b/src/layouts/PagesLayout.astro index 1dca91c..78acc5b 100644 --- a/src/layouts/PagesLayout.astro +++ b/src/layouts/PagesLayout.astro @@ -4,12 +4,8 @@ import BaseLayout from "./BaseLayout.astro"; import TOC from "../components/TOC.astro"; import Sidebar from "../components/Sidebar.astro"; -const { frontmatter, headings } = Astro.props; - -const posts = await Astro.glob("../pages/learn/**/*.{md,mdx}"); - -// The index.md page must have a `pagesLayout` frontmatter, which declares the order of all the pages. -const indexSubpath = `/learn/index.mdx`; +const { frontmatter, headings, posts: _posts, indexSubpath, basePath } = Astro.props; +const posts: Record[] = _posts; const indexPage = posts.find((post) => post.file.endsWith(indexSubpath)); @@ -66,7 +62,7 @@ function validateEntry(entry: PageEntry, basePath: string) { } for (const entry of pagesIndex) { - validateEntry(entry, `/learn/`); + validateEntry(entry, basePath); } --- @@ -82,7 +78,7 @@ for (const entry of pagesIndex) { diff --git a/src/layouts/SpecLayout.astro b/src/layouts/SpecLayout.astro new file mode 100644 index 0000000..e8cfb28 --- /dev/null +++ b/src/layouts/SpecLayout.astro @@ -0,0 +1,18 @@ +--- +import PagesLayout from "./PagesLayout.astro"; + +const { frontmatter, headings } = Astro.props; + +const posts = await Astro.glob("../pages/spec/**/*.{md,mdx}"); +const indexSubpath = `/spec/index.md`; +--- + + + + diff --git a/src/pages/learn/basics/comments.md b/src/pages/learn/basics/comments.md index e4cdb56..ca81669 100644 --- a/src/pages/learn/basics/comments.md +++ b/src/pages/learn/basics/comments.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Comments --- diff --git a/src/pages/learn/basics/datatypes.md b/src/pages/learn/basics/datatypes.md index 084c634..4837e36 100644 --- a/src/pages/learn/basics/datatypes.md +++ b/src/pages/learn/basics/datatypes.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Datatypes --- diff --git a/src/pages/learn/basics/hello-world.mdx b/src/pages/learn/basics/hello-world.mdx index 11c7b3d..710f37a 100644 --- a/src/pages/learn/basics/hello-world.mdx +++ b/src/pages/learn/basics/hello-world.mdx @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Hello world --- import InteractiveCode from "../../../components/InteractiveCode.astro"; diff --git a/src/pages/learn/basics/operators.md b/src/pages/learn/basics/operators.md index 925fad4..e17c88f 100644 --- a/src/pages/learn/basics/operators.md +++ b/src/pages/learn/basics/operators.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Operators --- diff --git a/src/pages/learn/basics/variables.md b/src/pages/learn/basics/variables.md index 416a3f0..74f1fab 100644 --- a/src/pages/learn/basics/variables.md +++ b/src/pages/learn/basics/variables.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Variables --- diff --git a/src/pages/learn/classes/anonymous.md b/src/pages/learn/classes/anonymous.md index 7d849fe..e722aa7 100644 --- a/src/pages/learn/classes/anonymous.md +++ b/src/pages/learn/classes/anonymous.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Anonymous classes --- # Anonymous classes diff --git a/src/pages/learn/classes/definition.md b/src/pages/learn/classes/definition.md index 2f48967..5b95c86 100644 --- a/src/pages/learn/classes/definition.md +++ b/src/pages/learn/classes/definition.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Classes --- diff --git a/src/pages/learn/classes/interfaces.md b/src/pages/learn/classes/interfaces.md index 648a0d1..235a710 100644 --- a/src/pages/learn/classes/interfaces.md +++ b/src/pages/learn/classes/interfaces.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Interfaces --- diff --git a/src/pages/learn/classes/magic.md b/src/pages/learn/classes/magic.md index bda80d1..1d9a7da 100644 --- a/src/pages/learn/classes/magic.md +++ b/src/pages/learn/classes/magic.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Magic methods --- diff --git a/src/pages/learn/classes/static.md b/src/pages/learn/classes/static.md index efadc26..3509318 100644 --- a/src/pages/learn/classes/static.md +++ b/src/pages/learn/classes/static.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Static --- diff --git a/src/pages/learn/data-structures/arrays.md b/src/pages/learn/data-structures/arrays.md index dc79315..c7e39d5 100644 --- a/src/pages/learn/data-structures/arrays.md +++ b/src/pages/learn/data-structures/arrays.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Arrays --- diff --git a/src/pages/learn/data-structures/enums.md b/src/pages/learn/data-structures/enums.md index 578e0c9..935014b 100644 --- a/src/pages/learn/data-structures/enums.md +++ b/src/pages/learn/data-structures/enums.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Enums --- diff --git a/src/pages/learn/data-structures/maps.md b/src/pages/learn/data-structures/maps.md index c8249f2..e0f4271 100644 --- a/src/pages/learn/data-structures/maps.md +++ b/src/pages/learn/data-structures/maps.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Maps --- diff --git a/src/pages/learn/data-structures/tuples.md b/src/pages/learn/data-structures/tuples.md index b9b264d..d43ecca 100644 --- a/src/pages/learn/data-structures/tuples.md +++ b/src/pages/learn/data-structures/tuples.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Tuples --- diff --git a/src/pages/learn/error-handling/null.md b/src/pages/learn/error-handling/null.md index 36d0e7b..1e4f54b 100644 --- a/src/pages/learn/error-handling/null.md +++ b/src/pages/learn/error-handling/null.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Nullable types --- diff --git a/src/pages/learn/error-handling/try.mdx b/src/pages/learn/error-handling/try.mdx index 49bf7fa..0c2ec84 100644 --- a/src/pages/learn/error-handling/try.mdx +++ b/src/pages/learn/error-handling/try.mdx @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Try/Exceptions --- import InteractiveCode from "../../../components/InteractiveCode.astro"; diff --git a/src/pages/learn/flow-control/blocks.md b/src/pages/learn/flow-control/blocks.md index 21afdee..1aa9737 100644 --- a/src/pages/learn/flow-control/blocks.md +++ b/src/pages/learn/flow-control/blocks.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Blocks --- diff --git a/src/pages/learn/flow-control/conditionals.md b/src/pages/learn/flow-control/conditionals.md index 369ff8d..3fabea4 100644 --- a/src/pages/learn/flow-control/conditionals.md +++ b/src/pages/learn/flow-control/conditionals.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Conditionals --- diff --git a/src/pages/learn/flow-control/loops.md b/src/pages/learn/flow-control/loops.md index 138404a..34d6eb3 100644 --- a/src/pages/learn/flow-control/loops.md +++ b/src/pages/learn/flow-control/loops.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Loops --- diff --git a/src/pages/learn/flow-control/match.md b/src/pages/learn/flow-control/match.md index 962c3a9..6419f81 100644 --- a/src/pages/learn/flow-control/match.md +++ b/src/pages/learn/flow-control/match.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Match --- diff --git a/src/pages/learn/functions/declaration.md b/src/pages/learn/functions/declaration.md index f08b659..ba2c1ae 100644 --- a/src/pages/learn/functions/declaration.md +++ b/src/pages/learn/functions/declaration.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Declaration --- diff --git a/src/pages/learn/functions/higher-order.md b/src/pages/learn/functions/higher-order.md index b6112ed..4b24183 100644 --- a/src/pages/learn/functions/higher-order.md +++ b/src/pages/learn/functions/higher-order.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Higher Order Functions --- diff --git a/src/pages/learn/functions/lambdas.md b/src/pages/learn/functions/lambdas.md index 02a31bd..03d1665 100644 --- a/src/pages/learn/functions/lambdas.md +++ b/src/pages/learn/functions/lambdas.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Lambdas --- diff --git a/src/pages/learn/functions/parameters.md b/src/pages/learn/functions/parameters.md index 8467517..f47bd6c 100644 --- a/src/pages/learn/functions/parameters.md +++ b/src/pages/learn/functions/parameters.md @@ -1,5 +1,5 @@ --- -layout: ../../../layouts/PagesLayout.astro +layout: ../../../layouts/DocsLayout.astro title: Function parameters --- diff --git a/src/pages/learn/index.mdx b/src/pages/learn/index.mdx index 8b0ea48..35a43d1 100644 --- a/src/pages/learn/index.mdx +++ b/src/pages/learn/index.mdx @@ -1,5 +1,5 @@ --- -layout: ../../layouts/PagesLayout.astro +layout: ../../layouts/DocsLayout.astro title: Welcome pagesLayout: - path: index diff --git a/src/pages/learn/install.md b/src/pages/learn/install.md index 8d54dfd..8505a34 100644 --- a/src/pages/learn/install.md +++ b/src/pages/learn/install.md @@ -1,5 +1,5 @@ --- -layout: ../../layouts/PagesLayout.astro +layout: ../../layouts/DocsLayout.astro title: Install --- diff --git a/src/pages/spec/ast/ast.md b/src/pages/spec/ast/ast.md new file mode 100644 index 0000000..223eb20 --- /dev/null +++ b/src/pages/spec/ast/ast.md @@ -0,0 +1,36 @@ +--- +layout: ../../../layouts/SpecLayout.astro +title: AST +--- + +# THP AST + +Created during the syntax analysis phase, from the stream of +tokens produced by the lexic analysis phase. + +## File and modules + +Every file has its own AST, and every file is a module. + +```ebnf +AST = Module + +Module = (Statement | Expression)* +``` + +## Statement + +(At the moment) a statement is either a variable binding or a function declaration + +```ebnf +Statement = VariableBinding + | FunctionDeclaration +``` + +## Expression + +See the Expression section + + + + diff --git a/src/pages/spec/index.md b/src/pages/spec/index.md new file mode 100644 index 0000000..a6f40b9 --- /dev/null +++ b/src/pages/spec/index.md @@ -0,0 +1,129 @@ +--- +layout: ../../layouts/SpecLayout.astro +title: Welcome +pagesLayout: +- path: index +- path: tokens + title: Tokens + children: + - path: tokens + - path: numbers + - path: identifier + - path: string + - path: comments + - path: operator + - path: grouping + - path: newline +- path: ast + title: THP AST + children: + - path: ast +--- + + +# The THP Language Specification + +This series of pages define the THP Programming Language. + +THP's grammar is context-dependant. + +The syntax is specified using a weird mix of Extended Backus Naur Form +and RegExp: + +```abnf +; comments + +syntax = concatenation +concatenation = alternation grouping + +alternation = "a" | "b" + | "c" +grouping = ("a", "b") + +optional = "a"? +one_or_more = "a"+ +zero_or_more = "a"* + +range = "1".."9" +literal = "a" +``` + +## Compiler architecture + +The compiler consists of 5 common phases: + +- **Lexical Analysis**: Transforms the source code into tokens +- **Syntactic Analysis**: Parses the tokens and generates an AST +- **Semantic Analysis**: Checks the AST structure and performs type checking +- **IR**: Transforms the THP AST into a PHP AST +- **Codegen**: Generates PHP source code from the PHP AST + + + +## Source Code representation + +Source code is encoded in UTF-8, and a single UTF-8 codepoint is +a single character. As THP is implemented using the Rust programming +language, rules around Rust's UTF-8 usage are followed. + + +## Basic characters + +Although the source code must be encoded in UTF-8, most of the actual +source code will use only the basic 128 ASCII characters. String contents may +contain any Unicode code point. + +```abnf +underscore = "_" + +decimal_digit = "0".."9" +binary_digit = "0" | "1" +octal_digit = "0".."7" +hex_digit = decimal_digit | "a".."f" | "A".."F" + +lowercase_letter = "a".."z" +uppercase_letter = "A".."Z" +``` + + + + +## Whitespace + +THP is partially whitespace sensitive. It uses the following tokens: Indent, Dedent & NewLine +to determine when an expression spans multiple lines. + +The lexer stores the indentation level of every line, and when scanning the next line, +compares the previous indentation to the new one. If the amount of whitespace is +greater than before, it emits a Indent token. If it's lower, emits a Dedent token, and +if it's the same it does nothing. + + +```thp +1 + 2 + + 3 + + 4 +``` + +The previous code would emit the following tokens: `1` `+` `2` `NewLine` `Indent` `+` `3` `NewLine` +`+` `4` `Dedent` + + +Additionaly, it is a lexical error to have wrong indentation. The lexer stores all +previous indentation levels in a stack, and reports an error if a decrease in indentation +doesn't match a previous level. + +```thp +if true { // 0 indentation + print() // 4 indentation + print() // 2 indentation. Error. There is no 2-indentation level +} +``` + +These tokens are used to detect when a expression is done, instead of relying on +semicolons. This is performed by the parser. + +Every other production of the grammar doesn't care about whitespace/indentation, so +those ignore whitespace. + + diff --git a/src/pages/spec/tokens/comments.md b/src/pages/spec/tokens/comments.md new file mode 100644 index 0000000..56fc41c --- /dev/null +++ b/src/pages/spec/tokens/comments.md @@ -0,0 +1,16 @@ +--- +layout: ../../../layouts/SpecLayout.astro +title: Comment +--- + +# Comment + +```ebnf +Comment = "//", any_except_new_line +``` + +```thp +// This is a comment +// +// Another // comment +``` diff --git a/src/pages/spec/tokens/grouping.md b/src/pages/spec/tokens/grouping.md new file mode 100644 index 0000000..db54ffa --- /dev/null +++ b/src/pages/spec/tokens/grouping.md @@ -0,0 +1,17 @@ +--- +layout: ../../../layouts/SpecLayout.astro +title: Grouping signs +--- + +# Grouping signs + +Each grouping sign has its own token: + +```ebnf +LeftParen = "(" +RightParen = ")" +LeftBracket = "[" +RightBracket = "]" +LeftBrace = "{" +RightBrace = "}" +``` diff --git a/src/pages/spec/tokens/identifier.md b/src/pages/spec/tokens/identifier.md new file mode 100644 index 0000000..0788dc3 --- /dev/null +++ b/src/pages/spec/tokens/identifier.md @@ -0,0 +1,54 @@ +--- +layout: ../../../layouts/SpecLayout.astro +title: Identifiers & Datatypes +--- + +# Identifiers & Datatypes + +Upper and lowercase letters carry different meaning when at the start of a word. + +A Datatype must always start with an uppercase letter, and an identifier must start +with either a lowercase letter or an underscore. + +## Identifier + +```ebnf +Identifier = (underscore | lowercase_letter), identifier_letter* + +identifier_letter = underscore | lowercase_letter | uppercase_letter | decimal_digit +``` + +```thp +identifier +_identifier +_123 +_many_letters +camelCase +``` + + +## Datatype + +```ebnf +Datatype = uppercase_letter, indentifier_letter* +``` + +```thp +Datatype +PDO +WEIRD_DATATYPE +``` + + +## Keywords + +The following are (currently) THP keywords: + +```thp +val var fun +``` + +Keywords are scanned first as identifiers, then transformed +to their respective tokens. + + diff --git a/src/pages/spec/tokens/newline.md b/src/pages/spec/tokens/newline.md new file mode 100644 index 0000000..cd35b5c --- /dev/null +++ b/src/pages/spec/tokens/newline.md @@ -0,0 +1,15 @@ +--- +layout: ../../../layouts/SpecLayout.astro +title: New line +--- + +# New line + +When there are multiple empty lines, only a single NewLine token +is emitted. + +```ebnf +NewLine = "\n", empty_line* + +empty_line = " "*, "\n" +``` diff --git a/src/pages/spec/tokens/numbers.md b/src/pages/spec/tokens/numbers.md new file mode 100644 index 0000000..a10df0a --- /dev/null +++ b/src/pages/spec/tokens/numbers.md @@ -0,0 +1,56 @@ +--- +layout: ../../../layouts/SpecLayout.astro +title: Numbers +--- + +# Numbers + +## Int + +```ebnf +Int = hexadecimal_number + | decimal_number + +hexadecimal_number = "0", ("x" | "X"), hexadecimal_digit+ +decimal_number = decimal_digit+ +``` + +```thp +12345 +01234 // This is a decimal number, not an octal number +0xff25 +0XFfaA +``` + +`TODO`: Implement octal `0o777` and binary `0b0110`. + +`TODO`: Allow underscores `_` between any number: `1_000_000`. + + +## Float + +```ebnf +Float = decimal_number, ".", decimal_number+, scientific_notation? + | decimal_number, scientific_notation + +scientific_notation = "e", ("+" | "-"), decimal_number +``` + +```thp +123.456 +123.456e+4 +123.456e-2 + +123e+10 +123e-3 +``` + + +All floating point numbers must start with at least 1 digit. + `.5` is not a valid floating point number. + + +`TODO`: Allow scientific notation to omit the `+`/`-`: `10e4`. + + + diff --git a/src/pages/spec/tokens/operator.md b/src/pages/spec/tokens/operator.md new file mode 100644 index 0000000..becfa6b --- /dev/null +++ b/src/pages/spec/tokens/operator.md @@ -0,0 +1,30 @@ +--- +layout: ../../../layouts/SpecLayout.astro +title: Operator +--- + +# Operator + + +```ebnf +Operator = operator_char+ + +operator_char = "+" | "-" | "=" | "*" | "!" | "/" | "|" + | "@" | "#" | "$" | "~" | "%" | "&" | "?" + | "<" | ">" | "^" | "." | ":" +``` + +```thp ++ - / * % < > <= >= -> => +``` + +These are all the characters that can make an operator. + +The lexer doesn't know about any operator in particular. +In other languages something like `+-1` would be interpreted +as `+` `-` `1`. In THP, this is always `+-` `1`, and that +would throw an error because the operator `+-` doesn't exist. + +## Comma + +Comma is its own token: `,`. diff --git a/src/pages/spec/tokens/string.md b/src/pages/spec/tokens/string.md new file mode 100644 index 0000000..e44bd10 --- /dev/null +++ b/src/pages/spec/tokens/string.md @@ -0,0 +1,29 @@ +--- +layout: ../../../layouts/SpecLayout.astro +title: String +--- + +# String + +A string is single line, delimited by double quotes `"` only. + +```ebnf +String = double_quote, (escape_seq | string_char)*, double_quote + +double_quote = '"' +escape_seq = "\n" + | '\"' + | "\r" + | "\\" + | "\t" +string_char = any_unicode_except_newline_and_double_quote +``` + +```thp +"hello" +"" +"it's me" +"\"Mario\"" +``` + +`TODO`: String interpolation diff --git a/src/pages/spec/tokens/tokens.md b/src/pages/spec/tokens/tokens.md new file mode 100644 index 0000000..dc41312 --- /dev/null +++ b/src/pages/spec/tokens/tokens.md @@ -0,0 +1,38 @@ +--- +layout: ../../../layouts/SpecLayout.astro +title: Index +--- + +# Tokens index + +These are all the THP tokens: + +```rust +pub enum TokenType { + Identifier, + Datatype, + Int, + Float, + String, + Operator, + LeftParen, + RightParen, + LeftBracket, + RightBracket, + LeftBrace, + RightBrace, + NewLine, + Comment, + Comma, + INDENT, + DEDENT, + VAL, + VAR, + EOF, + FUN, +} +``` + +Every keyword has its own token. + +