Browse Source

initial work on web ughr

feature/web
Amélia Liao 3 years ago
parent
commit
2ff359d1e9
25 changed files with 4162 additions and 23 deletions
  1. +14
    -0
      .gitignore
  2. +28
    -0
      Makefile
  3. +17
    -5
      cubical.cabal
  4. +5
    -5
      intro.tt
  5. +1
    -6
      src/Elab/Monad.hs
  6. +4
    -3
      src/Elab/WiredIn.hs
  7. +1
    -1
      src/Main.hs
  8. +6
    -1
      src/Presyntax/Presyntax.hs
  9. +1
    -1
      src/Syntax.hs
  10. +1
    -1
      src/Syntax/Pretty.hs
  11. +135
    -0
      src/Web.hs
  12. +8
    -0
      src/wrapper.mjs
  13. +7
    -0
      web/.gitignore
  14. +13
    -0
      web/deploy.sh
  15. +17
    -0
      web/html/index.html
  16. +3549
    -0
      web/package-lock.json
  17. +27
    -0
      web/package.json
  18. +71
    -0
      web/src/editor.ts
  19. +98
    -0
      web/src/index.ts
  20. +30
    -0
      web/src/language.ts
  21. +15
    -0
      web/src/toast.ts
  22. +14
    -0
      web/styles/main.css
  23. +33
    -0
      web/tsconfig.json
  24. +31
    -0
      web/typings/cubical.ts
  25. +36
    -0
      web/webpack.config.js

+ 14
- 0
.gitignore View File

@ -1 +1,15 @@
.stack-work/
dist-newstyle
*.hi-boot
*.o
*.o-boot
*.hi
src/Presyntax/Lexer.hs
src/Presyntax/Parser.hs
*.js
!web/interaction.js
*.wasm
cabal.project.local

+ 28
- 0
Makefile View File

@ -0,0 +1,28 @@
FUNCTIONS := $(shell grep -R "foreign" src/ | cut -d' ' -f4)
HS_FILES := $(shell find src -type f -name '*.hs' -or -name '*.hs-boot')
CABAL_OPTL := $(foreach function,$(FUNCTIONS),--ghc-option=-optl--export-function=$(function)) -f asterius
AHCD_OPTL := $(foreach function,$(FUNCTIONS),--export-function=$(function))
CABAL := ahc-cabal
AHCD := ahc-dist
web/dist/cubical.wasm: web/dist/cubical.js
cp dist-newstyle/cubical.wasm $@
web/dist/cubical.js: dist-newstyle/cubical.js
cp dist-newstyle/cubical.js $@
dist-newstyle/cubical.js: dist-newstyle/cubical src/wrapper.mjs
mkdir -p dist-newstyle/ahcd-spam
$(AHCD) $(AHCD_OPTL) --input-exe $< --browser --bundle --input-mjs src/wrapper.mjs
dist-newstyle/cubical: src/Presyntax/Lexer.hs src/Presyntax/Parser.hs $(HS_FILES)
$(CABAL) v2-install $(CABAL_OPTL) --installdir dist-newstyle exe:cubical --overwrite-policy=always
src/Presyntax/Lexer.hs: src/Presyntax/Lexer.x
alex $<
src/Presyntax/Parser.hs: src/Presyntax/Parser.y
happy $<

+ 17
- 5
cubical.cabal View File

@ -10,19 +10,25 @@ maintainer: [email protected]
copyright: 2021 Abigail Magalhães
category: Web
build-type: Simple
cabal-version: >=2.0
cabal-version: 2.0
extra-source-files: README.md
flag asterius
description: Is this build for the web?
manual: True
default: False
executable cubical
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base ^>= 4.14
build-depends: base >= 4.13
, mtl ^>= 2.2
, syb ^>= 0.7
, text ^>= 1.2
, array ^>= 0.5
, aeson >= 1.4
, containers ^>= 0.6
, bytestring ^>= 0.10
@ -46,8 +52,14 @@ executable cubical
, Elab.WiredIn
, Elab.Eval.Formula
build-tool-depends: alex:alex >= 3.2.4 && < 4.0
, happy:happy >= 1.19.12 && < 2.0
-- Asterius wrapper
, Web
ghc-options: -Wall -Wextra -Wno-name-shadowing
if !flag(asterius)
build-tool-depends: alex:alex >= 3.2.4 && < 4.0
, happy:happy >= 1.19.12 && < 2.0
if flag(asterius)
build-depends: asterius-prelude == 0.0.1
ghc-options: -Wall -Wextra -Wno-name-shadowing

+ 5
- 5
intro.tt View File

@ -293,11 +293,11 @@ transpFun : {A : Type} {B : Type} {C : Type} {D : Type} (p : Path A B) (q : Path
(\x -> transp (\i -> q i) (f (transp (\i -> p (inot i)) x)))
transpFun p q f = refl
-- transpDFun : {A : I -> Type} {B : (i : I) -> A i -> Type}
-- -> (f : (x : A i0) -> B i0 x)
-- -> Path (transp (\i -> (x : A i) -> B i x) f)
-- (\x -> transp (\i -> B i (fill (\j -> A (inot j)) (\k []) (inS x) (inot i))) (f (fill (\j -> A (inot j)) (\k []) (inS x) i1)))
-- transpDFun f = refl
transpDFun : {A : I -> Type} {B : (i : I) -> A i -> Type}
-> (f : (x : A i0) -> B i0 x)
-> Path (transp (\i -> (x : A i) -> B i x) f)
(\x -> transp (\i -> B i (fill (\j -> A (inot j)) (\k []) (inS x) (inot i))) (f (fill (\j -> A (inot j)) (\k []) (inS x) i1)))
transpDFun f = refl
-- When considering the more general case of a composition respecing sides,
-- the outer transport becomes a composition.


+ 1
- 6
src/Elab/Monad.hs View File

@ -115,12 +115,7 @@ getNameFor x = do
Nothing -> liftIO . throwIO $ NotInScope (Bound x 0)
switch :: ElabM a -> ElabM a
switch k =
do
depth <- asks pingPong
when (depth >= 128) $ throwElab StackOverflow
local go k
where go e = e { pingPong = pingPong e + 1 }
switch k = k
newtype NotInScope = NotInScope { nameNotInScope :: Name }
deriving (Show, Typeable)


+ 4
- 3
src/Elab/WiredIn.hs View File

@ -199,7 +199,9 @@ ielim line left right fn i =
VNe n sp -> VNe n (sp Seq.:|> PIElim line left right i)
VSystem map -> VSystem (fmap (flip (ielim line left right) i) map)
VInc (VPath _ _ _) _ u -> ielim line left right u i
VCase env r x xs -> VCase env r x (fmap (fmap (flip (IElim (quote line) (quote left) (quote right)) (quote i))) xs)
VCase env r x xs ->
let k x = IElim (quote line) (quote left) (quote right) x (quote i)
in VCase env r x (fmap (projIntoCase k) xs)
_ -> error $ "can't ielim " ++ show (prettyTm (quote fn))
outS :: HasCallStack => NFSort -> NFEndp -> Value -> Value -> Value
@ -237,7 +239,6 @@ comp a psi@phi u incA0@(compOutS (a @@ VI1) phi (u @@ VI1 @@ VItIsOne) -> a0) =
rng i = let VSigma _ (Closure _ r) = force (a @@ i) in r
w i = fill (fun dom) phi (system \i isone -> vProj1 (u @@ i @@ isone)) (VInc (dom VI0) phi (vProj1 a0)) i
-- c1 = comp (fun dom) phi (system \i isone -> vProj1 (u @@ i @@ isone)) (VInc (dom VI0) phi (vProj1 a0))
c2 = comp (fun \x -> rng x (w x)) phi (system \i isone -> vProj2 (u @@ i @@ isone)) (VInc (rng VI0 (w VI0)) phi (vProj2 a0))
in
VPair (w VI1) c2
@ -301,7 +302,7 @@ comp a psi@phi u incA0@(compOutS (a @@ VI1) phi (u @@ VI1 @@ VItIsOne) -> a0) =
VNe (HData False _) Seq.Empty -> a0
VNe (HData False _) args ->
case force a0 of
VNe (HCon con_type con_name) con_args ->
VNe (HCon con_type con_name) con_args ->
VNe (HCon con_type con_name) $ compConArgs (length args) (a @@) con_type con_args phi u
_ -> VComp a phi u (VInc (a @@ VI0) phi a0)


+ 1
- 1
src/Main.hs View File

@ -55,7 +55,7 @@ main = do
Check files verbose -> do
env <- checkFiles files
when verbose $ dumpEnv env
Repl -> enterReplIn =<< checkFiles ["./test.tt"]
Repl -> enterReplIn =<< emptyEnv
evalArgExpr :: ElabEnv -> String -> IO ()
evalArgExpr env str =


+ 6
- 1
src/Presyntax/Presyntax.hs View File

@ -1,9 +1,14 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
module Presyntax.Presyntax where
import Data.Aeson (ToJSON)
import Data.Text (Text)
import Data.Data
import GHC.Generics (Generic)
data Plicity
= Im | Ex
deriving (Eq, Show, Ord, Data)
@ -74,4 +79,4 @@ data Posn
= Posn { posnLine :: {-# UNPACK #-} !Int
, posnColm :: {-# UNPACK #-} !Int
}
deriving (Eq, Show, Ord)
deriving (Eq, Show, Ord, Generic, ToJSON)

+ 1
- 1
src/Syntax.hs View File

@ -212,7 +212,7 @@ quoteWith names (GluedVl h sp (VLam p (Closure n k))) =
quoteWith names (GluedVl h sp vl)
| GluedVl _ _ inner <- vl = quoteWith names (GluedVl h sp inner)
| True || alwaysShort vl = quoteWith names vl
| alwaysShort vl = quoteWith names vl
| otherwise = quoteWith names (VNe h sp)
quoteWith names (VLam p (Closure n k)) =


+ 1
- 1
src/Syntax/Pretty.hs View File

@ -33,7 +33,7 @@ prettyTm = prettyTm . everywhere (mkT beautify) where
prettyTm (PCon _ v) = keyword (pretty v)
prettyTm (Data _ v) = operator (pretty v)
prettyTm (App Im f x) = parenFun f <+> braces (prettyTm x)
prettyTm (App Im f _) = prettyTm f
prettyTm (App Ex f x) = parenFun f <+> parenArg x
prettyTm (Pair x y) = parens $ prettyTm x <> operator comma <+> prettyTm y


+ 135
- 0
src/Web.hs View File

@ -0,0 +1,135 @@
{-# LANGUAGE CPP #-}
module Web where
import Control.Exception.Base
import Control.Monad.Reader
import qualified Data.ByteString.Lazy as Bsl
import qualified Data.Text.Encoding as T
import qualified Data.Map.Strict as Map
import qualified Data.Text as T
import Elab.Eval (zonkIO, force)
import Elab.Monad
import Elab
import Foreign
import Presyntax.Presyntax
import Presyntax.Parser
import Presyntax.Lexer
import Syntax.Pretty
import Syntax
#ifdef ASTERIUS
import Asterius.Types
import Asterius.Aeson
#endif
parseFromString :: String -> IO (StablePtr [Statement])
parseFromString str = do
case runAlex (Bsl.fromStrict (T.encodeUtf8 inp)) parseProg of
Right e -> newStablePtr e
Left e -> throwIO (ErrorCall e)
where
inp = T.pack str
newEnvironment :: IO (StablePtr ElabEnv)
newEnvironment = newStablePtr =<< emptyEnv
typeCheckProgram :: StablePtr ElabEnv -> StablePtr [Statement] -> IO (StablePtr ElabEnv)
typeCheckProgram envP prog =
do
prog <- deRefStablePtr prog
env <- runElab (go prog) =<< deRefStablePtr envP
newStablePtr env
where
go prog = checkProgram prog ask
getTypeByName :: String -> StablePtr ElabEnv -> IO (StablePtr Value)
getTypeByName str env = do
env <- deRefStablePtr env
case Map.lookup (T.pack str) (nameMap env) of
Just nm -> newStablePtr (fst (getEnv env Map.! nm))
Nothing -> throwIO (NotInScope (Bound (T.pack str) 0))
getValueByName :: String -> StablePtr ElabEnv -> IO (StablePtr Value)
getValueByName str env = do
env <- deRefStablePtr env
case Map.lookup (T.pack str) (nameMap env) of
Just nm -> newStablePtr (snd (getEnv env Map.! nm))
Nothing -> throwIO (NotInScope (Bound (T.pack str) 0))
classifyValue :: StablePtr Value -> IO String
classifyValue val = do
t <- deRefStablePtr val
pure $ case force t of
VNe (HData pathcs _) _
| pathcs -> "data.higher"
| otherwise -> "data"
VNe (HCon _ _) _ -> "constr"
_ -> "other"
classifyValueByName :: String -> StablePtr ElabEnv -> IO String
classifyValueByName str env = do
env <- deRefStablePtr env
case Map.lookup (T.pack str) (nameMap env) of
Just nm ->
pure $ case force (snd (getEnv env Map.! nm)) of
VNe (HData pathcs _) _
| pathcs -> "constr.data.higher"
| otherwise -> "constr.data"
VNe HPCon{} _ -> "constr.higher"
VNe HCon{} _ -> "constr"
_ -> "other"
Nothing -> throwIO $ NotInScope (Bound (T.pack str) 0)
findDefinition :: String -> StablePtr ElabEnv -> IO (Maybe (Posn, Posn))
findDefinition str env = do
env <- deRefStablePtr env
case Map.lookup (T.pack str) (nameMap env) of
Just nm -> pure $ Map.lookup nm (whereBound env)
Nothing -> throwIO $ NotInScope (Bound (T.pack str) 0)
zonkAndShowType :: StablePtr Value -> IO String
zonkAndShowType val = do
val <- deRefStablePtr val
val <- zonkIO val
let str = show . prettyTm . quote $ val
pure str
freeHaskellValue :: StablePtr a -> IO ()
freeHaskellValue = freeStablePtr
#ifdef ASTERIUS
parseFromStringJs :: JSString -> IO (StablePtr [Statement])
parseFromStringJs = parseFromString . fromJSString
getTypeByNameJs :: JSString -> StablePtr ElabEnv -> IO (StablePtr Value)
getTypeByNameJs str env = getTypeByName (fromJSString str) env
getValueByNameJs :: JSString -> StablePtr ElabEnv -> IO (StablePtr Value)
getValueByNameJs str env = getValueByName (fromJSString str) env
zonkAndShowTypeJs :: StablePtr Value -> IO JSString
zonkAndShowTypeJs = fmap toJSString . zonkAndShowType
classifyValueByNameJs :: JSString -> StablePtr ElabEnv -> IO JSString
classifyValueByNameJs str env = toJSString <$> classifyValueByName (fromJSString str) env
findDefinitionJs :: JSString -> StablePtr ElabEnv -> IO JSVal
findDefinitionJs str env = jsonToJSVal <$> findDefinition (fromJSString str) env
foreign export javascript parseFromStringJs :: JSString -> IO (StablePtr [Statement])
foreign export javascript getTypeByNameJs :: JSString -> StablePtr ElabEnv -> IO (StablePtr Value)
foreign export javascript getValueByNameJs :: JSString -> StablePtr ElabEnv -> IO (StablePtr Value)
foreign export javascript classifyValueByNameJs :: JSString -> StablePtr ElabEnv -> IO JSString
foreign export javascript newEnvironment :: IO (StablePtr ElabEnv)
foreign export javascript typeCheckProgram :: StablePtr ElabEnv -> StablePtr [Statement] -> IO (StablePtr ElabEnv)
foreign export javascript zonkAndShowTypeJs :: StablePtr Value -> IO JSString
foreign export javascript freeHaskellValue :: StablePtr Value -> IO ()
foreign export javascript findDefinitionJs :: JSString -> StablePtr ElabEnv -> IO JSVal
#endif

+ 8
- 0
src/wrapper.mjs View File

@ -0,0 +1,8 @@
import * as rts from "./rts.mjs";
import module from "./cubical.wasm.mjs";
import req from "./cubical.req.mjs";
document.addEventListener('DOMContentLoaded', async () => {
window.cubical = await module.then(m => rts.newAsteriusInstance(Object.assign(req, {module: m})))
document.dispatchEvent(new Event('cubicalLoaded'));
});

+ 7
- 0
web/.gitignore View File

@ -0,0 +1,7 @@
/node_modules
/native_modules
/dist
*.tsbuildinfo
!/webpack.config.js

+ 13
- 0
web/deploy.sh View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
if which ahc-cabal &>/dev/null; then
pushd ..
make
popd
fi
cp ../intro.tt dist/ -rv
cp html/* dist/ -rv
cp styles/* dist/ -rv
rsync dist/ ${SYNC_SERVER}:/var/www/demo.inductive.properties -avx

+ 17
- 0
web/html/index.html View File

@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<title>cubical</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="/main.css" />
<script type="text/javascript" src="/cubical.js"></script>
<script type="text/javascript" src="/bundle.js"></script>
</head>
<body>
<pre class="editor-container" style="height: 100vh;" src="/intro.tt"></pre>
</body>
</html>

+ 3549
- 0
web/package-lock.json
File diff suppressed because it is too large
View File


+ 27
- 0
web/package.json View File

@ -0,0 +1,27 @@
{
"name": "cubical-frontend",
"version": "1.0.0",
"description": "Web frontend for cubical",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://git.abby.how/abby/cubical"
},
"author": "Abigail",
"license": "MIT",
"dev-dependencies": {
"typescript": "^4.2.3"
},
"devDependencies": {
"css-loader": "^5.1.3",
"file-loader": "^6.2.0",
"monaco-editor-webpack-plugin": "^3.0.1",
"style-loader": "^2.0.0",
"ts-loader": "^8.0.18",
"typescript": "^4.2.3",
"webpack-cli": "^4.5.0"
}
}

+ 71
- 0
web/src/editor.ts View File

@ -0,0 +1,71 @@
import * as monaco from 'monaco-editor';
import { CubicalT, Environment, Value } from '../typings/cubical';
import * as haskell from '../typings/cubical';
let editorNum: number = 0;
let cubical: CubicalT;
export const MODEL_ENVS: Record<string, Environment> = {}
async function reloadModelEnv(model: monaco.editor.ITextModel, environ: Environment): Promise<void> {
console.log(`reloading environment for model ${model.id}`)
let code, typed;
try {
code = await cubical.exports.parseFromStringJs(model.getValue());
typed = await cubical.exports.typeCheckProgram(environ, code);
MODEL_ENVS[model.id] = typed;
} catch (e) {
if (typeof (e) === 'string')
console.log(e);
}
}
export class CubicalEditor {
private model: monaco.editor.ITextModel;
private editor: monaco.editor.IStandaloneCodeEditor;
private environment: Environment | undefined;
private uri: monaco.Uri;
private element: HTMLElement;
private didChangeLocked: boolean;
constructor(el: HTMLElement, code: string, uri: monaco.Uri) {
this.element = el;
this.uri = uri;
this.model = monaco.editor.createModel(code, 'cubical', this.uri);
this.editor = monaco.editor.create(el, {
model: this.model,
tabSize: 2,
insertSpaces: true,
})
this.didChangeLocked = false;
}
async load() {
cubical = await haskell.waitForLoad;
this.environment = await cubical.exports.newEnvironment();
this.model.onDidChangeContent(async (e) => {
if (this.didChangeLocked) {
console.log("going too fast");
return;
}
this.didChangeLocked = true;
console.log('doing the work')
// reloadModelEnv(this.model!, this.environment!);
setTimeout(() => {
this.didChangeLocked = false;
}, 1000);
});
this.editor.layout();
reloadModelEnv(this.model, this.environment);
window.addEventListener('resize', () => this.editor.layout());
}
}

+ 98
- 0
web/src/index.ts View File

@ -0,0 +1,98 @@
import * as monaco from 'monaco-editor';
import { CubicalT, Environment, Value } from '../typings/cubical';
import * as haskell from '../typings/cubical';
import language from './language';
import toast from './toast';
import { CubicalEditor, MODEL_ENVS } from './editor';
let initCode: string[] = [
"{-# PRIMITIVE Type #-}",
"",
"data Nat : Type where",
" zero : Nat",
" succ : Nat -> Nat",
"",
"test : Nat",
"test = succ zero"
]
declare const cubical: CubicalT;
const LANGUAGE: string = "cubical";
monaco.languages.register({
id: LANGUAGE
});
monaco.languages.registerHoverProvider(LANGUAGE, {
provideHover: async (model: monaco.editor.ITextModel, position: monaco.Position, token: monaco.CancellationToken) => {
const word = model.getWordAtPosition(position);
if (!word) return;
try {
const env: Environment | null = MODEL_ENVS[model.id];
if (!env) return null;
const ty: Value = await cubical.exports.getTypeByNameJs(word.word, env);
return {
contents: [{
value: await cubical.exports.zonkAndShowTypeJs(ty)
}]
}
} catch (e) {
return null;
}
}
});
monaco.languages.registerDefinitionProvider(LANGUAGE, {
provideDefinition: async (model: monaco.editor.ITextModel, position: monaco.Position, token: monaco.CancellationToken) => {
const word = model.getWordAtPosition(position);
if (!word) return [];
try {
const env: Environment | null = MODEL_ENVS[model.id];
if (!env) return [];
const range: haskell.Range | null = await cubical.exports.findDefinitionJs(word.word, env);
if (range) {
return [{
range: {
startColumn: range[0].posnColm,
endColumn: range[1].posnColm,
startLineNumber: range[0].posnLine,
endLineNumber: range[1].posnLine,
},
uri: model.uri,
}];
} else {
return [];
}
} catch (e) {
console.log(e);
return [];
}
}
})
monaco.languages.setMonarchTokensProvider(LANGUAGE, language);
document.addEventListener('DOMContentLoaded', async () => {
let editors: CubicalEditor[] = [];
let n = 0;
document.querySelectorAll("pre.editor-container").forEach(async (theEl) => {
let el = theEl as HTMLPreElement;
let attr = el.getAttribute("src");
let text : string;
if (attr) {
text = await fetch(attr).then(x => x.text());
} else {
text = el.innerText;
}
el.innerText = '';
let editor = new CubicalEditor(el, text, monaco.Uri.parse(attr ?? `editor://${n++}`));
await editor.load();
})
});

+ 30
- 0
web/src/language.ts View File

@ -0,0 +1,30 @@
import * as monaco from 'monaco-editor';
const language: monaco.languages.IMonarchLanguage = {
ignoreCase: false,
brackets: [
{ open: '(', close: ')', token: 'delimiter.parens' },
{ open: '[', close: ']', token: 'delimiter.square' },
{ open: '{', close: '}', token: 'delimiter.curly' },
],
tokenizer: {
"normal": [
[/\{\-#/, 'comment', '@pragma'],
[/\[/, 'delimiter.square', '@system'],
[/\-\-.*$/, 'comment'],
[/\b(data|where|case|as|in|postulate|let|where)\b/, 'keyword'],
[/(=|:|\-\>|\\)/, 'keyword']
],
"pragma": [
[/PRIMITIVE/, 'keyword'],
[/#\-\}/, 'comment', '@pop']
],
"system": [
[/\b(i0|i1)/, 'keyword'],
[/\]/, 'delimiter.square', '@pop'],
{ include: "normal" }
]
}
};
export default language;

+ 15
- 0
web/src/toast.ts View File

@ -0,0 +1,15 @@
export default function toast(duration: number, message: HTMLElement | string): void {
let element = document.createElement('div');
element.classList.add("toast");
if (typeof(message) == 'string') {
element.innerText = message;
} else {
element.appendChild(message);
}
document.body.appendChild(element);
setTimeout(() => {
element.remove();
}, duration * 1000);
}

+ 14
- 0
web/styles/main.css View File

@ -0,0 +1,14 @@
html {
padding: 0;
margin: 0;
height: 100vh;
width: 100vw;
}
body {
height: 100%;
width: 70%;
margin: auto;
overflow-x: hidden;
}

+ 33
- 0
web/tsconfig.json View File

@ -0,0 +1,33 @@
{
"compilerOptions": {
"target": "es6",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"outDir": "./dist/",
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"downlevelIteration": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noImplicitAny": true,
"jsx": "react-jsx",
"typeRoots": [
"./node_modules/@types",
"./typings"
]
},
"include": [
"src",
"typings"
]
}

+ 31
- 0
web/typings/cubical.ts View File

@ -0,0 +1,31 @@
export class Program { };
export class Environment { };
export class Value { };
export type Posn = {
posnLine: number,
posnColm: number
};
export type Range = [Posn, Posn];
export type CubicalT = {
exports: {
parseFromStringJs(s: string): Promise<Program>;
newEnvironment(): Promise<Environment>;
typeCheckProgram(p: Environment, e: Program): Promise<Environment>;
zonkAndShowTypeJs(val: Value): Promise<string>;
getTypeByNameJs(name: string, e: Environment): Promise<Value>;
getValueByNameJs(name: string, e: Environment): Promise<Value>;
classifyValueByNameJs(name: string, e: Environment): Promise<string>;
findDefinitionJs(name: string, e: Environment): Promise<Range | null>;
}
};
export const waitForLoad : Promise<CubicalT> = new Promise(resolve =>
document.addEventListener('cubicalLoaded', () => {
resolve((window as unknown as { cubical: CubicalT}).cubical)
}));

+ 36
- 0
web/webpack.config.js View File

@ -0,0 +1,36 @@
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.ttf$/,
use: ['file-loader']
}
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
plugins: [
new MonacoWebpackPlugin({
languages: [],
})
]
};

Loading…
Cancel
Save