Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DL2: start adding scoping rules (in DL2) #445

Merged
merged 14 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions apps/languageWorkbench/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import useHashParam from "use-hash-param";
import { ErrorList } from "../../uiCommon/ide/errorList";
import { addCursor } from "../../languageWorkbench/interpCache";
import { CollapsibleWithHeading } from "../../uiCommon/generic/collapsible";
import { LanguageSpec } from "../../languageWorkbench/common/types";
import {
LanguageSpec,
dl as dl1,
dl2,
} from "../../languageWorkbench/common/types";
import { CACHE } from "../../languageWorkbench/vscode/common";

function Main() {
Expand All @@ -26,7 +30,10 @@ function Workbench() {

const curLangSpec: LanguageSpec = {
name: versionedLangID,
datalog: curLangState.datalog.source,
logic:
curLangState.datalogVersion === "DL1"
? dl1(curLangState.datalog.source)
: dl2(curLangState.datalog.source),
example: curLangState.example.source,
grammar: curLangState.grammar.source,
};
Expand Down Expand Up @@ -152,13 +159,15 @@ type LangState = {
example: EditorState;
grammar: EditorState;
datalog: EditorState;
datalogVersion: "DL1" | "DL2";
};

const emptyState: State = mapObj(LANGUAGES, (langID, spec) => ({
version: 1,
example: { cursorPos: 1, source: spec.example },
grammar: { cursorPos: 1, source: spec.grammar },
datalog: { cursorPos: 1, source: spec.datalog },
datalog: { cursorPos: 1, source: spec.logic.source },
datalogVersion: spec.logic.type,
}));

type Action = { type: "UpdateLang"; langID: string; action: LangAction };
Expand Down
4 changes: 2 additions & 2 deletions languageWorkbench/benchmarks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { InterpCache, addCursor } from "./interpCache";
import { AbstractInterpreter } from "../core/abstractInterpreter";
import * as fs from "fs";
import { assertDeepEqual } from "../util/testBench/testing";
import { LanguageSpec } from "./common/types";
import { LanguageSpec, dl } from "./common/types";
import { SimpleInterpreter } from "../core/simple/interpreter";
import { fsLoader } from "../core/fsLoader";
import { IncrementalInterpreter } from "../core/incremental/interpreter";
Expand Down Expand Up @@ -229,7 +229,7 @@ const flattenedByRule = flattenByRule(ruleTree, input, LEAVES);

const langSpec: LanguageSpec = {
name: "datalog",
datalog: fs.readFileSync(`languageWorkbench/languages/dl/dl.dl`, "utf8"),
logic: dl(fs.readFileSync(`languageWorkbench/languages/dl/dl.dl`, "utf8")),
grammar: fs.readFileSync(`languageWorkbench/languages/dl/dl.grammar`, "utf8"),
example: "",
};
Expand Down
14 changes: 13 additions & 1 deletion languageWorkbench/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,26 @@ import { Grammar, Span } from "../parserlib/types";

export type LanguageSpec = {
name: string;
datalog: string;
logic: LogicSpec;
grammar: string;
example: string;
triggerCharacters?: string[]; // TODO: put into DL itself or derive from grammar
nativeImpl?: LangImpl;
leaves?: Set<string>;
};

export type LogicSpec =
| { type: "DL1"; source: string }
| { type: "DL2"; source: string };

export function dl(source: string): LogicSpec {
return { type: "DL1", source };
}

export function dl2(source: string): LogicSpec {
return { type: "DL2", source };
}

export type LangImpl = {
grammar: Grammar;
scopeDefn: (
Expand Down
24 changes: 14 additions & 10 deletions languageWorkbench/ddTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import { datalogOut, plainTextOut } from "../util/ddTest/types";
import * as fs from "fs";
import { Suite } from "../util/testBench/testing";
import { LanguageSpec } from "./common/types";
import { LanguageSpec, dl, dl2 } from "./common/types";
import { IncrementalInterpreter } from "../core/incremental/interpreter";
import { compile } from "./languages/dl2/compile";
import { extractModule } from "./languages/dl2/extract";
Expand Down Expand Up @@ -105,11 +105,17 @@ function dl2RunTest(test: string[]): TestOutput[] {
const decls = lines.slice(0, lines.length - 1).join("\n");
const query = lines[lines.length - 1];

let interp: AbstractInterpreter = new SimpleInterpreter(
BASE_PATH,
fsLoader
);

// TODO: get parse problems
const [interp, problems] = instantiate(parseMain(decls));
const [newInterp, problems] = instantiate(interp, decls);
if (problems.length > 0) {
throw new Error(`problems: ${problems}`);
}
interp = newInterp;

// Query
const res = interp.queryStr(query);
Expand All @@ -127,16 +133,14 @@ export function testLangQuery(
const exampleWithCursor = lines.slice(1, lines.length - 1).join("\n");
const { input: example, cursorPos } = extractCursor(exampleWithCursor);
const query = lines[lines.length - 1];

const basePath = `languageWorkbench/languages/${langName}/${langName}`;
const langSpec: LanguageSpec = {
name: langName,
datalog: fs.readFileSync(
`languageWorkbench/languages/${langName}/${langName}.dl`,
"utf8"
),
grammar: fs.readFileSync(
`languageWorkbench/languages/${langName}/${langName}.grammar`,
"utf8"
),
logic: fs.existsSync(`${basePath}.dl2`)
? dl2(fs.readFileSync(`${basePath}.dl2`, "utf8"))
: dl(fs.readFileSync(`${basePath}.dl`, "utf8")),
grammar: fs.readFileSync(`${basePath}.grammar`, "utf8"),
example: "",
};
const { interp: withoutCursor } = cache.getInterpForDoc(
Expand Down
20 changes: 18 additions & 2 deletions languageWorkbench/interpCache.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AbstractInterpreter } from "../core/abstractInterpreter";
import { LanguageSpec } from "./common/types";
import { instantiate } from "./languages/dl2/instantiate";
import { parseMain } from "./languages/grammar/parser";
import { declareTables, flatten, getUnionRule } from "./parserlib/flatten";
import { parse, TraceTree } from "./parserlib/parser";
Expand Down Expand Up @@ -114,8 +115,23 @@ export class InterpCache {

// add datalog
try {
if (langSpec.datalog.length > 0) {
interp = interp.evalStr(langSpec.datalog)[1];
switch (langSpec.logic.type) {
case "DL1": {
interp = interp.evalStr(langSpec.logic.source)[1];
break;
}
case "DL2": {
const [newInterp, problems] = instantiate(
interp,
langSpec.logic.source
);
// TODO: show in UI
if (problems.length > 0) {
console.error("DL2 extraction problems", problems);
}
interp = newInterp;
break;
}
}
interp = interp.evalRawStmts(declareTables(grammar))[1];
interp = interp.evalStmt({
Expand Down
4 changes: 2 additions & 2 deletions languageWorkbench/languages/basicBlocks/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LanguageSpec } from "../../common/types";
import { LanguageSpec, dl } from "../../common/types";
// @ts-ignore
import datalog from "./basicBlocks.dl";
// @ts-ignore
Expand All @@ -8,7 +8,7 @@ import example from "./example.txt";

export const basicBlocks: LanguageSpec = {
name: "basicBlocks",
datalog,
logic: dl(datalog),
grammar,
example,
};
4 changes: 2 additions & 2 deletions languageWorkbench/languages/contracts/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LanguageSpec } from "../../common/types";
import { LanguageSpec, dl } from "../../common/types";
// @ts-ignore
import datalog from "./contracts.dl";
// @ts-ignore
Expand All @@ -8,7 +8,7 @@ import example from "./example.txt";

export const contracts: LanguageSpec = {
name: "contracts",
datalog,
logic: dl(datalog),
grammar,
example,
};
4 changes: 2 additions & 2 deletions languageWorkbench/languages/dl/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LanguageSpec } from "../../common/types";
import { LanguageSpec, dl } from "../../common/types";
import { datalogLangImpl } from "./dl";
// @ts-ignore
import datalogTxt from "./dl.dl";
Expand All @@ -9,7 +9,7 @@ import example from "./example.txt";

export const datalog: LanguageSpec = {
name: "datalog",
datalog: datalogTxt,
logic: dl(datalogTxt),
grammar,
example,
// TODO: derive these from the grammar
Expand Down
4 changes: 2 additions & 2 deletions languageWorkbench/languages/dl2/compile.dd.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
table post {
author_id,
comment: inRef(comment.post_id)
comment: inRef(comment:post_id)
}
table comment {
author_id,
Expand All @@ -20,7 +20,7 @@ postComment{commentID: C, postID: P} :- post{id: P} & comment{id: C, post_id: P}

table post {
author_id,
comment: inRef(comment.post_id)
comment: inRef(comment:post_id)
}
table comment {
author_id,
Expand Down
6 changes: 3 additions & 3 deletions languageWorkbench/languages/dl2/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ function extractNested(
path: Path
): [Conjunct[], ExtractionProblem[]] {
const relation =
path.length === 0 ? nested.ident.text : path[path.length - 1].relation;
path.length === 0 ? nested.qualifier.text : path[path.length - 1].relation;
const curRec = rec(relation, {});
if (path.length > 0) {
const last = path[path.length - 1];
Expand All @@ -127,14 +127,14 @@ function extractNested(
case "NormalAttr":
continue;
case "Nested": {
const attrName = attr.ident.text;
const attrName = attr.qualifier.text;
const refSpec = mod.tableDecls[relation].members[attrName];
if (!refSpec) {
problems.push({
type: "MissingRefSpec",
relation,
name: attrName,
span: attr.ident.span,
span: attr.qualifier.span,
});
continue;
}
Expand Down
12 changes: 0 additions & 12 deletions languageWorkbench/languages/dl2/dl2.dl

This file was deleted.

68 changes: 68 additions & 0 deletions languageWorkbench/languages/dl2/dl2.dl2
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
table ast.rule {
record: inRef(ast.record:parentID)
}
table ast.record {
qualifier: inRef(ast.qualifier:parentID)
}
table ast.tableDecl {
qualifier: inRef(ast.qualifier:parentID),
attr: inRef(ast.tableAttr:parentID)
}
table ast.tableAttr {
ident: inRef(ast.ident:parentID)
}

def scope.Defn{scopeID: I, span: S, name: N, kind: K, type: "any"} {
scope.defnRule{scopeID: I, span: S, name: N, kind: K} |
scope.defnTable{scopeID: I, span: S, name: N, kind: K} |
scope.defnAttr{scopeID: I, span: S, name: N, kind: K}
}

def scope.defnRule{scopeID: global{}, span: S, name: N, kind: "relation"} {
ast.rule {
record {
qualifier {
text: N,
span: S
}
}
}
}

def scope.defnTable{scopeID: global{}, span: S, name: N, kind: "relation"} {
ast.tableDecl {
qualifier {
text: N,
span: S
}
}
}

def scope.defnAttr{scopeID: I, span: S, name: N, kind: "attr"} {
ast.tableDecl {
qualifier {
text: I
},
attr {
ident {
text: N,
span: S
}
}
}
}

table hl.mapping {}

hl.mapping{rule: "ident", type: "ident"}.
hl.mapping{rule: "var", type: "typeParameter"}.
hl.mapping{rule: "int", type: "number"}.
hl.mapping{rule: "bool", type: "number"}.
hl.mapping{rule: "string", type: "string"}.
hl.mapping{rule: "comment", type: "comment"}.
hl.mapping{rule: "tableKW", type: "keyword"}.
hl.mapping{rule: "importKW", type: "keyword"}.
hl.mapping{rule: "inRefKW", type: "keyword"}.
hl.mapping{rule: "outRefKW", type: "keyword"}.
hl.mapping{rule: "defKW", type: "keyword"}.
hl.mapping{rule: "path", type: "string"}.
9 changes: 5 additions & 4 deletions languageWorkbench/languages/dl2/dl2.grammar
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ declaration :- (rule | tableDecl | import | fact).
comment :- ["#", repSep(commentChar, "")].
import :- [importKW, ws, path].

# TODO: probably shouldn't allow qualifiers here
tableDecl :- [
tableKW, ws, name:ident, ws, "{", ws,
tableKW, ws, name:qualifier, ws, "{", ws,
repSep(tableAttr, commaSpace), ws,
"}"
].
tableAttr :- [ident, (refSpec | "")].
refSpec :- [":", ws, (outRef | inRef)].
outRef :- ["outRef", "(", table:ident, ".", col:ident, ")"].
inRef :- ["inRef", "(", table:ident, ".", col:ident, ")"].
outRef :- ["outRef", "(", table:qualifier, ":", col:ident, ")"].
inRef :- ["inRef", "(", table:qualifier, ":", col:ident, ")"].

inRefKW :- "inRef".
outRefKW :- "outRef".
Expand All @@ -33,7 +34,7 @@ aggregation :- [aggregation:ident, "[", repSep(var, commaSpace), ":", ws, record
comparison :- [left:term, ws, comparisonOp, ws, right:term].
comparisonOp :- ("<=" | ">=" | ">" | "<" | "=" | "!=").

nested :- [ident, ws, "{", ws, repSep(nestedAttr, commaSpace), ws, "}"].
nested :- [qualifier, ws, "{", ws, repSep(nestedAttr, commaSpace), ws, "}"].
nestedAttr :- (normalAttr | nested).
normalAttr :- [ident, ":", ws, term].

Expand Down
2 changes: 1 addition & 1 deletion languageWorkbench/languages/dl2/example.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import "ast"

table constraint {
id,
record: inRef(record.parentID)
record: inRef(record:parentID)
}

def varInComparison{scope: I, name: N, span: S} {
Expand Down
6 changes: 3 additions & 3 deletions languageWorkbench/languages/dl2/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { LanguageSpec } from "../../common/types";
import { LanguageSpec, dl2 } from "../../common/types";
// @ts-ignore
import datalog from "./dl2.dl";
import datalog from "./dl2.dl2";
// @ts-ignore
import grammar from "./dl2.grammar";
// @ts-ignore
import example from "./example.txt";

export const datalog2: LanguageSpec = {
name: "datalog2",
datalog,
logic: dl2(datalog),
grammar,
example,
};
Loading
Loading