Skip to content

Commit

Permalink
Merged with main
Browse files Browse the repository at this point in the history
  • Loading branch information
OAGr committed Jan 20, 2024
2 parents 84e1778 + 524e387 commit c5c5c31
Show file tree
Hide file tree
Showing 48 changed files with 786 additions and 386 deletions.
6 changes: 6 additions & 0 deletions .changeset/angry-bears-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@quri/squiggle-lang": patch
"@quri/squiggle-components": patch
---

Fixes error with "Find in editor" and tooltips not working for decorated values
5 changes: 5 additions & 0 deletions .changeset/stupid-bananas-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@quri/squiggle-lang": patch
---

Disallow capitalized variable names that we allowed by accident in 0.9.0
7 changes: 7 additions & 0 deletions packages/components/babel.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = {
presets: [
["@babel/preset-env", { targets: { node: "current" } }],
"@babel/preset-typescript",
["@babel/preset-react", { runtime: "automatic" }],
],
};
13 changes: 2 additions & 11 deletions packages/components/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
/** @type {import('jest').Config} */
const jestConfig = {
preset: "ts-jest/presets/default-esm-legacy",
testEnvironment: "jsdom",
extensionsToTreatAsEsm: [".ts", ".tsx"],
setupFilesAfterEnv: ["<rootDir>/test/setup.ts"],
moduleNameMapper: {
"^(\\.{1,2}/.*)\\.js$": "$1",
},
transform: {
"^.+\\.tsx?$": [
"ts-jest",
{
useESM: true,
tsconfig: "tsconfig.tests.json",
},
],
},
testPathIgnorePatterns: ["<rootDir>/node_modules/", "<rootDir>/dist"],
};

Expand Down
8 changes: 5 additions & 3 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
"@hookform/resolvers": "^3.3.3",
"@lezer/common": "^1.2.0",
"@quri/prettier-plugin-squiggle": "workspace:*",
"@quri/squiggle-textmate-grammar": "workspace:*",
"@quri/squiggle-lang": "workspace:*",
"@quri/squiggle-textmate-grammar": "workspace:*",
"@quri/ui": "workspace:*",
"@react-hook/size": "^2.1.2",
"@tailwindcss/typography": "^0.5.10",
Expand All @@ -45,12 +45,14 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@quri/configs": "workspace:*",
"@babel/preset-react": "^7.23.3",
"@babel/preset-typescript": "^7.23.3",
"@jest/globals": "^29.7.0",
"@juggle/resize-observer": "^3.4.0",
"@lezer/generator": "^1.5.1",
"@lezer/highlight": "^1.2.0",
"@lezer/lr": "^1.3.14",
"@quri/configs": "workspace:*",
"@storybook/addon-actions": "^7.6.6",
"@storybook/addon-docs": "^7.6.6",
"@storybook/addon-essentials": "^7.6.6",
Expand All @@ -73,6 +75,7 @@
"@typescript-eslint/eslint-plugin": "^6.16.0",
"@typescript-eslint/parser": "^6.16.0",
"@wogns3623/eslint-plugin-better-exhaustive-deps": "^1.1.0",
"babel-jest": "^29.7.0",
"canvas": "^2.11.2",
"eslint": "^8.56.0",
"eslint-plugin-react": "^7.33.2",
Expand All @@ -88,7 +91,6 @@
"rollup-plugin-node-builtins": "^2.1.2",
"storybook": "^7.6.7",
"tailwindcss": "^3.4.0",
"ts-jest": "^29.1.1",
"typescript": "^5.3.3",
"vite": "^5.0.10"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/components/CodeEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export type CodeEditorProps = {
showGutter?: boolean;
lineWrapping?: boolean;
errors?: SqError[];
sourceId?: string;
sourceId: string;
fontSize?: number;
project: SqProject;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,59 @@ import {
} from "@codemirror/autocomplete";
import { syntaxTree } from "@codemirror/language";
import { SyntaxNode, Tree } from "@lezer/common";
import { createRoot } from "react-dom/client";

import { SqProject } from "@quri/squiggle-lang";

import { FnDocumentationFromName } from "../../ui/FnDocumentation.js";
import { reactAsDom } from "../utils.js";

export function getNameNodes(tree: Tree, from: number) {
type NameNode = {
node: SyntaxNode;
type: "function" | "variable";
};

export function getNameNodes(tree: Tree, from: number): NameNode[] {
const cursor = tree.cursorAt(from, -1);
const nameNodes: SyntaxNode[] = [];
const nameNodes: NameNode[] = [];

// We walk up and backwards through the tree, looking for nodes that have names.

let direction: "start" | "sibling" | "parent" | undefined = "start";
while (1) {
// Only for sibling nodes; `foo = { <cursor> }` shouldn't autocomplete `foo`.
if (cursor.type.is("Binding") && direction === "sibling") {
const nameNode = cursor.node.getChild("VariableName");
if (nameNode) {
nameNodes.push(nameNode);
if (cursor.type.is("Statement") && direction === "sibling") {
// Only for sibling nodes; `foo = { <cursor> }` shouldn't autocomplete `foo`.

// Unwrap decorated statements.
let node: SyntaxNode | null = cursor.node;
while (node && node.type.is("DecoratedStatement")) {
node = node.getChild("Statement");
}
// Only for sibling nodes; Squiggle doesn't support recursive calls.
} else if (cursor.type.is("FunDeclaration") && direction === "sibling") {
const nameNode = cursor.node.getChild("FunctionName");
if (nameNode) {
nameNodes.push(nameNode);

const nameNode = node?.getChild("VariableName");
if (node && nameNode) {
nameNodes.push({
node: nameNode,
type: node?.type.is("DefunStatement") ? "function" : "variable",
});
}
} else if (cursor.type.is("FunDeclaration") && direction !== "sibling") {
} else if (cursor.type.is("DefunStatement") && direction !== "sibling") {
// Function declaration that's a parent, let's autocomplete its parameter names.
// Note that we also allow `direction === "start"`, to handle `f(foo) = foo` correctly.
const parameterNodes =
cursor.node.getChild("LambdaArgs")?.getChildren("LambdaParameter") ??
[];

for (const parameter of parameterNodes) {
const nameNode = parameter.getChild("LambdaParameterName");
if (nameNode) {
nameNodes.push(nameNode);
nameNodes.push({
node: nameNode,
// Is there a more specific type? There's no "parameter" type in CodeMirror.
// https://codemirror.net/docs/ref/#autocomplete.Completion.type
type: "variable",
});
}
}
} else if (cursor.type.is("Decorator") && direction !== "sibling") {
// TODO
}

// Move to the next node and store the direction that we used.
Expand All @@ -64,12 +78,7 @@ export function makeCompletionSource(project: SqProject) {
const decoratorCompletions: Completion[] = [];

const getInfoFunction = (name: string): Completion["info"] => {
return () => {
const dom = document.createElement("div");
const root = createRoot(dom);
root.render(<FnDocumentationFromName functionName={name} />);
return { dom };
};
return () => reactAsDom(<FnDocumentationFromName functionName={name} />);
};

for (const [name, value] of project.getStdLib().entrySeq()) {
Expand Down Expand Up @@ -106,24 +115,26 @@ export function makeCompletionSource(project: SqProject) {
snippetCompletion("|${args}| ${body}", {
label: "|",
detail: "lambda function",
type: "syntax",
type: "text",
}),
],
};
}
}

{
const identifier = cmpl.tokenBefore(["AccessExpr", "IdentifierExpr"]);
const identifier = cmpl.tokenBefore(["AccessExpr", "Identifier"]);
if (identifier) {
const { from } = identifier;
const nameNodes = getNameNodes(tree, from);
const localCompletions = nameNodes.map((node): Completion => {
const name = cmpl.state.doc.sliceString(node.from, node.to);
const type = node.type.is("FunctionName") ? "function" : "variable";
const localCompletions = nameNodes.map((nameNode): Completion => {
const name = cmpl.state.doc.sliceString(
nameNode.node.from,
nameNode.node.to
);
return {
label: name,
type,
type: nameNode.type,
};
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ export const lightThemeHighlightingStyle = HighlightStyle.define([
],
color: numbers,
},
{
tag: [tags.escape],
color: escapes,
},
{ tag: tags.escape, color: escapes },
{
tag: [
tags.operator,
Expand All @@ -67,7 +64,7 @@ export const lightThemeHighlightingStyle = HighlightStyle.define([
fontWeight: "bold",
color: operators,
},
{ tag: [tags.meta, tags.comment], color: comments },
{ tag: tags.comment, color: comments },
{ tag: tags.strong, fontWeight: "bold" },
{ tag: tags.emphasis, fontStyle: "italic" },
{ tag: tags.strikethrough, textDecoration: "line-through" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ commaSep<content> {
// when trailing comma is allowed
commaSep1<content> { "" | content ("," content?)* }

Binding { export? VariableName { identifier } "=" expression }
LetStatement { export? VariableName { identifier } "=" expression }

LambdaParameter {
LambdaParameterName { identifier } (":" expression)?
Expand All @@ -50,7 +50,7 @@ LambdaArgs {
() | LambdaParameter ("," LambdaParameter)*
}

FunDeclaration { export? FunctionName { identifier } ~callOrDeclaration "(" LambdaArgs ")" "=" expression }
DefunStatement { export? VariableName { identifier } ~callOrDeclaration "(" LambdaArgs ")" "=" expression }

Decorator {
"@" DecoratorName { identifier }
Expand All @@ -60,64 +60,62 @@ Decorator {
)
}

statement {
Decorator*
(
Binding
| FunDeclaration
)
statement[@isGroup="Statement"] {
LetStatement
| DefunStatement
| DecoratedStatement { Decorator statement }
}

expression {
expressionWithoutParens
| ( "(" expression ")" )
}

expression[@isGroup="Expression"] {
expressionWithoutParens[@isGroup="Expression"] {
String
| Boolean
| Boolean { @specialize[@name="Boolean"]<identifier, "true" | "false"> }
| Number
| BlockExpr { "{" blockContent "}" }
| DictExpr {
| Block { "{" blockContent "}" }
| Dict {
"{"
commaSep1<
Entry { Field[@dynamicPrecedence=1] { expression } ~inheritAmbig ":" expression }
KeyValue { Field[@dynamicPrecedence=1] { expression } ~inheritAmbig ":" expression }
| InheritEntry { Field[@dynamicPrecedence=0] { identifier } ~inheritAmbig }
>
"}"
}
| LambdaExpr { "{" ArgsOpen { "|" } LambdaArgs "|" blockContent "}" }
| IfExpr { if expression then expression !else else expression }
| ParenExpr { "(" expression ")" }
| IdentifierExpr { identifier }
| Lambda { "{" ArgsOpen { "|" } LambdaArgs "|" blockContent "}" }
| Identifier { identifier }
| AccessExpr { expression !deref "." Field { identifier } }
| CallExpr { expression ~callOrDeclaration !call "(" commaSep<Argument { expression }> ")" }
| TernaryExpr { expression !logop LogicOp<"?"> expression LogicOp<":"> expression }
| KVAccessExpr { expression !call ("[" Key { expression } "]") }
| ArrayExpr { "[" commaSep1<expression> "]" }
| UnaryExpr { !unary (ArithOp<"-"> | ArithOp<"!"> | DotArithOp<".-">) expression }
| LogicExpr {
| Call { expression ~callOrDeclaration !call "(" commaSep<Argument { expression }> ")" }
| TernaryC { expression !logop LogicOp<"?"> expression LogicOp<":"> expression }
| TernaryIfThenElse { if expression then expression !else else expression }
| BracketLookup { expression !call ("[" Key { expression } "]") }
| Array { "[" commaSep1<expression> "]" }
| UnaryCall { !unary (ArithOp<"-"> | ArithOp<"!"> | DotArithOp<".-">) expression }
| InfixCall {
expression !or LogicOp<"||"> expression
| expression !and LogicOp<"&&"> expression
| expression !rel LogicOp<">"> expression
| expression !rel LogicOp<"<"> expression
| expression !rel LogicOp<"<="> expression
| expression !rel LogicOp<">="> expression
| expression !rel LogicOp<"=="> expression
}
| ControlExpr {
expression !control ControlOp<"->"> expression
}
| ArithExpr {
expression !times ( ArithOp<"*"> | DotArithOp<".*"> ) expression
| expression !times ( ArithOp<"*"> | DotArithOp<".*"> ) expression
| expression !times ( ArithOp<"/"> | DotArithOp<"./"> ) expression
| expression !exp ( ArithOp<"^"> | DotArithOp<".^"> ) expression
| expression !plus ( ArithOp<"+"> | DotArithOp<".+"> ) expression
| expression !plus ( ArithOp<"-"> | DotArithOp<".-"> ) expression
| expression !plus @extend[@name="ArithOp"]<identifier, "to"> expression
}
| Pipe {
expression !control ControlOp<"->"> expression
}
}

// use `@extend` instead of `@specialize`, because keywords are valid variable names in Squiggle, for now.
kw<term> { @extend[@name={term}]<identifier, term> }


Boolean { @specialize[@name="Boolean"]<identifier, "true" | "false"> }

kw<term> { @specialize[@name={term}]<identifier, term> }
if { kw<"if"> }
then { kw<"then"> }
else { kw<"else"> }
Expand Down
Loading

0 comments on commit c5c5c31

Please sign in to comment.