Compare commits
3 Commits
b378756c5d
...
2c7508c2a4
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c7508c2a4 | |||
| 82722ec9e4 | |||
| 04c2137fe2 |
10
package.json
10
package.json
|
|
@ -1,11 +1,15 @@
|
||||||
{
|
{
|
||||||
"name": "shrimp",
|
"name": "shrimp",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"exports": "./src/index.ts",
|
"exports": {
|
||||||
|
".": "./src/index.ts",
|
||||||
|
"./editor": "./src/editor/index.ts",
|
||||||
|
"./editor.css": "./src/editor/editor.css"
|
||||||
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"editor": "bun --hot src/editor/server.tsx",
|
"editor": "bun --hot src/editor/example/server.tsx",
|
||||||
"repl": "bun bin/repl",
|
"repl": "bun bin/repl",
|
||||||
"update-reef": "rm -rf ~/.bun/install/cache/ && rm bun.lock && bun update reefvm",
|
"update-reef": "rm -rf ~/.bun/install/cache/ && rm bun.lock && bun update reefvm",
|
||||||
"cli:install": "ln -s \"$(pwd)/bin/shrimp\" ~/.bun/bin/shrimp",
|
"cli:install": "ln -s \"$(pwd)/bin/shrimp\" ~/.bun/bin/shrimp",
|
||||||
|
|
@ -33,4 +37,4 @@
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"printWidth": 100
|
"printWidth": 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,2 +1,102 @@
|
||||||
// Autocomplete for Shrimp
|
import { autocompletion, type CompletionContext, type Completion } from '@codemirror/autocomplete'
|
||||||
// TODO: Keywords and prelude function names
|
import { Shrimp, type Value } from '#/index'
|
||||||
|
|
||||||
|
const keywords = [
|
||||||
|
'import',
|
||||||
|
'end',
|
||||||
|
'do',
|
||||||
|
'if',
|
||||||
|
'else',
|
||||||
|
'while',
|
||||||
|
'try',
|
||||||
|
'catch',
|
||||||
|
'finally',
|
||||||
|
'throw',
|
||||||
|
'not',
|
||||||
|
'and',
|
||||||
|
'or',
|
||||||
|
'true',
|
||||||
|
'false',
|
||||||
|
'null',
|
||||||
|
]
|
||||||
|
|
||||||
|
const keywordCompletions: Completion[] = keywords.map((k) => ({
|
||||||
|
label: k,
|
||||||
|
type: 'keyword',
|
||||||
|
boost: -1,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const buildFunctionCompletion = (name: string, value: unknown): Completion => {
|
||||||
|
let detail: string | undefined
|
||||||
|
|
||||||
|
console.log(`🌭`, { name, fn: value?.toString() })
|
||||||
|
|
||||||
|
// console.log(`🌭`, { name, value })
|
||||||
|
|
||||||
|
// const isFunction = value?.type === 'function'
|
||||||
|
// if (isFunction) {
|
||||||
|
// const paramStrs = value.params.map((p) => (p in value.defaults ? `${p}?` : p))
|
||||||
|
|
||||||
|
// if (value.variadic && paramStrs.length > 0) {
|
||||||
|
// paramStrs[paramStrs.length - 1] = `...${paramStrs[paramStrs.length - 1]}`
|
||||||
|
// }
|
||||||
|
|
||||||
|
// detail = `(${paramStrs.join(', ')})`
|
||||||
|
// }
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: name,
|
||||||
|
type: 'function',
|
||||||
|
detail,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createShrimpCompletions = (shrimp: Shrimp) => {
|
||||||
|
// Build completions from all names in the shrimp scope
|
||||||
|
const scopeNames = shrimp.vm.scope.vars()
|
||||||
|
const functionCompletions: Completion[] = scopeNames.map((name) =>
|
||||||
|
buildFunctionCompletion(name, shrimp.get(name))
|
||||||
|
)
|
||||||
|
|
||||||
|
const allCompletions = [...keywordCompletions, ...functionCompletions]
|
||||||
|
|
||||||
|
// Get methods for a module (e.g., math, str, list)
|
||||||
|
const getModuleMethods = (moduleName: string): Completion[] => {
|
||||||
|
const module = shrimp.get(moduleName)
|
||||||
|
if (!module || module.type !== 'dict') return []
|
||||||
|
|
||||||
|
return Array.from(module.value.keys()).map((name) =>
|
||||||
|
buildFunctionCompletion(name, module.value.get(name))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const shrimpCompletionSource = (context: CompletionContext) => {
|
||||||
|
// Check for module.method pattern (e.g., "math.")
|
||||||
|
const dotMatch = context.matchBefore(/[\w\-]+\.[\w\-\?]*/)
|
||||||
|
if (dotMatch) {
|
||||||
|
const [moduleName, methodPrefix] = dotMatch.text.split('.')
|
||||||
|
const methods = getModuleMethods(moduleName!)
|
||||||
|
|
||||||
|
if (methods.length > 0) {
|
||||||
|
const dotPos = dotMatch.from + moduleName!.length + 1
|
||||||
|
return {
|
||||||
|
from: dotPos,
|
||||||
|
options: methods.filter((m) => m.label.startsWith(methodPrefix ?? '')),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular completions
|
||||||
|
const word = context.matchBefore(/[\w\-\?\$]+/)
|
||||||
|
if (!word || (word.from === word.to && !context.explicit)) return null
|
||||||
|
|
||||||
|
return {
|
||||||
|
from: word.from,
|
||||||
|
options: allCompletions.filter((c) => c.label.startsWith(word.text)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return autocompletion({
|
||||||
|
override: [shrimpCompletionSource],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,23 @@ import { linter, type Diagnostic } from '@codemirror/lint'
|
||||||
import { Shrimp } from '#/index'
|
import { Shrimp } from '#/index'
|
||||||
import { CompilerError } from '#compiler/compilerError'
|
import { CompilerError } from '#compiler/compilerError'
|
||||||
|
|
||||||
const shrimp = new Shrimp()
|
export const createShrimpDiagnostics = (shrimp: Shrimp) =>
|
||||||
|
linter((view) => {
|
||||||
|
const code = view.state.doc.toString()
|
||||||
|
const diagnostics: Diagnostic[] = []
|
||||||
|
|
||||||
export const shrimpDiagnostics = linter((view) => {
|
try {
|
||||||
const code = view.state.doc.toString()
|
shrimp.parse(code)
|
||||||
const diagnostics: Diagnostic[] = []
|
} catch (err) {
|
||||||
|
if (err instanceof CompilerError) {
|
||||||
try {
|
diagnostics.push({
|
||||||
shrimp.parse(code)
|
from: err.from,
|
||||||
} catch (err) {
|
to: err.to,
|
||||||
if (err instanceof CompilerError) {
|
severity: 'error',
|
||||||
diagnostics.push({
|
message: err.message,
|
||||||
from: err.from,
|
})
|
||||||
to: err.to,
|
}
|
||||||
severity: 'error',
|
|
||||||
message: err.message,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return diagnostics
|
return diagnostics
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
:root {
|
||||||
|
/* Background colors */
|
||||||
|
--bg-editor: #011627;
|
||||||
|
--bg-output: #40318D;
|
||||||
|
--bg-status-bar: #1E2A4A;
|
||||||
|
--bg-status-border: #0E1A3A;
|
||||||
|
--bg-selection: #1D3B53;
|
||||||
|
|
||||||
|
/* Text colors */
|
||||||
|
--text-editor: #D6DEEB;
|
||||||
|
--text-output: #7C70DA;
|
||||||
|
--text-status: #B3A9FF55;
|
||||||
|
--caret: #80A4C2;
|
||||||
|
|
||||||
|
/* Syntax highlighting colors */
|
||||||
|
--color-keyword: #C792EA;
|
||||||
|
--color-function: #82AAFF;
|
||||||
|
--color-string: #C3E88D;
|
||||||
|
--color-number: #F78C6C;
|
||||||
|
--color-bool: #FF5370;
|
||||||
|
--color-operator: #89DDFF;
|
||||||
|
--color-paren: #676E95;
|
||||||
|
--color-function-call: #FF9CAC;
|
||||||
|
--color-variable-def: #FFCB6B;
|
||||||
|
--color-error: #FF6E6E;
|
||||||
|
--color-regex: #E1ACFF;
|
||||||
|
|
||||||
|
/* ANSI terminal colors */
|
||||||
|
--ansi-black: #011627;
|
||||||
|
--ansi-red: #FF5370;
|
||||||
|
--ansi-green: #C3E88D;
|
||||||
|
--ansi-yellow: #FFCB6B;
|
||||||
|
--ansi-blue: #82AAFF;
|
||||||
|
--ansi-magenta: #C792EA;
|
||||||
|
--ansi-cyan: #89DDFF;
|
||||||
|
--ansi-white: #D6DEEB;
|
||||||
|
|
||||||
|
/* ANSI bright colors (slightly more vibrant) */
|
||||||
|
--ansi-bright-black: #676E95;
|
||||||
|
--ansi-bright-red: #FF6E90;
|
||||||
|
--ansi-bright-green: #D4F6A8;
|
||||||
|
--ansi-bright-yellow: #FFE082;
|
||||||
|
--ansi-bright-blue: #A8C7FA;
|
||||||
|
--ansi-bright-magenta: #E1ACFF;
|
||||||
|
--ansi-bright-cyan: #A8F5FF;
|
||||||
|
--ansi-bright-white: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'C64ProMono';
|
||||||
|
src: url('../../assets/C64_Pro_Mono-STYLE.woff2') format('woff2');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Pixeloid Mono';
|
||||||
|
src: url('../../assets/PixeloidMono.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--bg-editor);
|
||||||
|
font-family: 'Pixeloid Mono', 'Courier New', monospace;
|
||||||
|
font-size: 18px;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
@ -1,30 +1,70 @@
|
||||||
import { EditorView, basicSetup } from 'codemirror'
|
import { EditorView, basicSetup } from 'codemirror'
|
||||||
import { render } from 'hono/jsx/dom'
|
import { Shrimp } from '#/index'
|
||||||
|
|
||||||
import { shrimpTheme } from './theme'
|
import { shrimpTheme } from './theme'
|
||||||
import { shrimpDiagnostics } from './diagnostics'
|
import { createShrimpDiagnostics } from './diagnostics'
|
||||||
import { persistencePlugin, getContent } from './persistence'
|
|
||||||
import { shrimpHighlighter } from './highlighter'
|
import { shrimpHighlighter } from './highlighter'
|
||||||
|
import { createShrimpCompletions } from './completions'
|
||||||
|
import { shrimpKeymap } from './keymap'
|
||||||
|
import { getContent, persistence } from './persistence'
|
||||||
|
|
||||||
export const Editor = () => {
|
type EditorProps = {
|
||||||
|
initialCode?: string
|
||||||
|
onChange?: (code: string) => void
|
||||||
|
extensions?: import('@codemirror/state').Extension[]
|
||||||
|
shrimp?: Shrimp
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Editor = ({
|
||||||
|
initialCode = '',
|
||||||
|
onChange,
|
||||||
|
extensions: customExtensions = [],
|
||||||
|
shrimp = new Shrimp(),
|
||||||
|
}: EditorProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={(el: Element) => {
|
ref={(el: Element) => {
|
||||||
if (!el?.querySelector('.cm-editor')) createEditorView(el)
|
if (!el?.querySelector('.cm-editor'))
|
||||||
|
createEditorView(el, getContent() ?? initialCode, onChange, customExtensions, shrimp)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const createEditorView = (el: Element) => {
|
const createEditorView = (
|
||||||
|
el: Element,
|
||||||
|
initialCode: string,
|
||||||
|
onChange: ((code: string) => void) | undefined,
|
||||||
|
customExtensions: import('@codemirror/state').Extension[],
|
||||||
|
shrimp: Shrimp
|
||||||
|
) => {
|
||||||
|
const extensions = [
|
||||||
|
basicSetup,
|
||||||
|
shrimpTheme,
|
||||||
|
createShrimpDiagnostics(shrimp),
|
||||||
|
createShrimpCompletions(shrimp),
|
||||||
|
shrimpHighlighter,
|
||||||
|
shrimpKeymap,
|
||||||
|
persistence,
|
||||||
|
...customExtensions,
|
||||||
|
]
|
||||||
|
|
||||||
|
if (onChange) {
|
||||||
|
extensions.push(
|
||||||
|
EditorView.updateListener.of((update) => {
|
||||||
|
if (update.docChanged) {
|
||||||
|
onChange(update.state.doc.toString())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
new EditorView({
|
new EditorView({
|
||||||
parent: el,
|
parent: el,
|
||||||
doc: getContent() || '# type some code\necho hello',
|
doc: initialCode,
|
||||||
extensions: [basicSetup, shrimpTheme, shrimpDiagnostics, persistencePlugin, shrimpHighlighter],
|
extensions,
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// Mount when running in browser
|
// Trigger onChange with initial content
|
||||||
if (typeof document !== 'undefined') {
|
onChange?.(initialCode)
|
||||||
render(<Editor />, document.getElementById('root')!)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
src/editor/example/frontend.tsx
Normal file
6
src/editor/example/frontend.tsx
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { Editor } from '#editor/editor'
|
||||||
|
import { render } from 'hono/jsx/dom'
|
||||||
|
|
||||||
|
if (typeof document !== 'undefined') {
|
||||||
|
render(<Editor initialCode={'# type some code'} />, document.getElementById('root')!)
|
||||||
|
}
|
||||||
11
src/editor/example/index.html
Normal file
11
src/editor/example/index.html
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="stylesheet" href="../editor.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="./frontend.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -2,6 +2,7 @@ import { EditorView, Decoration, DecorationSet, ViewPlugin, ViewUpdate } from '@
|
||||||
import { RangeSetBuilder } from '@codemirror/state'
|
import { RangeSetBuilder } from '@codemirror/state'
|
||||||
import { Shrimp } from '#/index'
|
import { Shrimp } from '#/index'
|
||||||
import { type SyntaxNode } from '#parser/node'
|
import { type SyntaxNode } from '#parser/node'
|
||||||
|
import { log } from '#utils/utils'
|
||||||
|
|
||||||
const shrimp = new Shrimp()
|
const shrimp = new Shrimp()
|
||||||
|
|
||||||
|
|
@ -14,9 +15,9 @@ export const shrimpHighlighter = ViewPlugin.fromClass(
|
||||||
}
|
}
|
||||||
|
|
||||||
update(update: ViewUpdate) {
|
update(update: ViewUpdate) {
|
||||||
if (update.docChanged) {
|
if (!update.docChanged) return
|
||||||
this.decorations = this.highlight(update.view)
|
|
||||||
}
|
this.decorations = this.highlight(update.view)
|
||||||
}
|
}
|
||||||
|
|
||||||
highlight(view: EditorView): DecorationSet {
|
highlight(view: EditorView): DecorationSet {
|
||||||
|
|
@ -30,7 +31,8 @@ export const shrimpHighlighter = ViewPlugin.fromClass(
|
||||||
tree.iterate({
|
tree.iterate({
|
||||||
enter: (node) => {
|
enter: (node) => {
|
||||||
const cls = tokenStyles[node.type.name]
|
const cls = tokenStyles[node.type.name]
|
||||||
if (cls && isLeaf(node)) {
|
const isLeaf = node.children.length === 0
|
||||||
|
if (cls && isLeaf) {
|
||||||
decorations.push({ from: node.from, to: node.to, class: cls })
|
decorations.push({ from: node.from, to: node.to, class: cls })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -42,8 +44,8 @@ export const shrimpHighlighter = ViewPlugin.fromClass(
|
||||||
for (const d of decorations) {
|
for (const d of decorations) {
|
||||||
builder.add(d.from, d.to, Decoration.mark({ class: d.class }))
|
builder.add(d.from, d.to, Decoration.mark({ class: d.class }))
|
||||||
}
|
}
|
||||||
} catch {
|
} catch (error) {
|
||||||
// Parse failed, no highlighting
|
log('Parsing error in highlighter', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.finish()
|
return builder.finish()
|
||||||
|
|
@ -69,8 +71,3 @@ const tokenStyles: Record<string, string> = {
|
||||||
operator: 'tok-operator',
|
operator: 'tok-operator',
|
||||||
Regex: 'tok-regex',
|
Regex: 'tok-regex',
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if node is a leaf (should be highlighted)
|
|
||||||
const isLeaf = (node: SyntaxNode): boolean => {
|
|
||||||
return node.children.length === 0
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="root"></div>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#root {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
height: 100vh;
|
|
||||||
width: 100vw;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script type="module" src="./editor.tsx"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
1
src/editor/index.ts
Normal file
1
src/editor/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { Editor } from './editor'
|
||||||
8
src/editor/keymap.ts
Normal file
8
src/editor/keymap.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { keymap } from '@codemirror/view'
|
||||||
|
import { acceptCompletion } from '@codemirror/autocomplete'
|
||||||
|
import { indentWithTab } from '@codemirror/commands'
|
||||||
|
|
||||||
|
export const shrimpKeymap = keymap.of([
|
||||||
|
{ key: 'Tab', run: acceptCompletion },
|
||||||
|
indentWithTab,
|
||||||
|
])
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { ViewPlugin, ViewUpdate } from '@codemirror/view'
|
import { ViewPlugin, ViewUpdate } from '@codemirror/view'
|
||||||
|
|
||||||
export const persistencePlugin = ViewPlugin.fromClass(
|
export const persistence = ViewPlugin.fromClass(
|
||||||
class {
|
class {
|
||||||
saveTimeout?: ReturnType<typeof setTimeout>
|
saveTimeout?: ReturnType<typeof setTimeout>
|
||||||
|
|
||||||
|
|
@ -17,13 +17,13 @@ export const persistencePlugin = ViewPlugin.fromClass(
|
||||||
destroy() {
|
destroy() {
|
||||||
if (this.saveTimeout) clearTimeout(this.saveTimeout)
|
if (this.saveTimeout) clearTimeout(this.saveTimeout)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
export const getContent = () => {
|
export const getContent = () => {
|
||||||
return localStorage.getItem('shrimp-editor-content') || ''
|
return localStorage.getItem('shrimp-editor-content') || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const setContent = (data: string) => {
|
export const setContent = (data: string) => {
|
||||||
localStorage.setItem('shrimp-editor-content', data)
|
localStorage.setItem('shrimp-editor-content', data)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,12 @@ export const shrimpTheme = EditorView.theme(
|
||||||
fontFamily: '"Pixeloid Mono", "Courier New", monospace',
|
fontFamily: '"Pixeloid Mono", "Courier New", monospace',
|
||||||
caretColor: 'var(--caret)',
|
caretColor: 'var(--caret)',
|
||||||
padding: '0px',
|
padding: '0px',
|
||||||
|
borderTop: '1px solid var(--bg-editor)',
|
||||||
},
|
},
|
||||||
'&.cm-focused .cm-cursor': {
|
'&.cm-focused .cm-cursor': {
|
||||||
borderLeftColor: 'var(--caret)',
|
borderLeftColor: 'var(--caret)',
|
||||||
},
|
},
|
||||||
'&.cm-focused .cm-selectionBackground, ::selection': {
|
'.cm-selectionLayer .cm-selectionBackground': {
|
||||||
backgroundColor: 'var(--bg-selection)',
|
backgroundColor: 'var(--bg-selection)',
|
||||||
},
|
},
|
||||||
'.cm-editor': {
|
'.cm-editor': {
|
||||||
|
|
@ -31,8 +32,20 @@ export const shrimpTheme = EditorView.theme(
|
||||||
backgroundColor: 'var(--color-string)',
|
backgroundColor: 'var(--color-string)',
|
||||||
},
|
},
|
||||||
'.cm-activeLine': {
|
'.cm-activeLine': {
|
||||||
backgroundColor: 'var(--bg-active-line)',
|
backgroundColor: 'rgba(255, 255, 255, 0.03)',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Token highlighting
|
||||||
|
'.tok-keyword': { color: 'var(--color-keyword)' },
|
||||||
|
'.tok-string': { color: 'var(--color-string)' },
|
||||||
|
'.tok-number': { color: 'var(--color-number)' },
|
||||||
|
'.tok-bool': { color: 'var(--color-bool)' },
|
||||||
|
'.tok-null': { color: 'var(--color-number)', fontStyle: 'italic' },
|
||||||
|
'.tok-identifier': { color: 'var(--color-function)' },
|
||||||
|
'.tok-variable-def': { color: 'var(--color-variable-def)' },
|
||||||
|
'.tok-comment': { color: 'var(--ansi-bright-black)', fontStyle: 'italic' },
|
||||||
|
'.tok-operator': { color: 'var(--color-operator)' },
|
||||||
|
'.tok-regex': { color: 'var(--color-regex)' },
|
||||||
},
|
},
|
||||||
{ dark: true }
|
{ dark: true }
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
const DEBUG = process.env.DEBUG || false
|
import { isDebug } from '#utils/utils'
|
||||||
|
|
||||||
export type Token = {
|
export type Token = {
|
||||||
type: TokenType
|
type: TokenType
|
||||||
|
|
@ -169,11 +169,11 @@ export class Scanner {
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
},
|
},
|
||||||
valueTokens.has(type) ? { value: this.input.slice(from, to) } : {},
|
valueTokens.has(type) ? { value: this.input.slice(from, to) } : {}
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (DEBUG) {
|
if (isDebug()) {
|
||||||
const tok = this.tokens.at(-1)
|
const tok = this.tokens.at(-1)
|
||||||
console.log(`≫ PUSH(${from},${to})`, TokenType[tok?.type || 0], '—', tok?.value)
|
console.log(`≫ PUSH(${from},${to})`, TokenType[tok?.type || 0], '—', tok?.value)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user