import { describe, expect, it } from "vitest"; import { parse } from "../parse"; import { program, simple, stmt } from "../test-helpers/ast-builders"; describe("parse (phase 1: simple commands)", () => { it("parses empty input", () => { expect(parse("")).toMatchAst({ ast: program() }); }); it("parses a single simple command", () => { expect(parse("foo")).toMatchAst({ ast: program(stmt(simple("foo"))) }); }); it("parses multiple statements separated by newline or semicolon", () => { expect(parse("foo\nbar")).toMatchAst({ ast: program(stmt(simple("foo")), stmt(simple("bar"))), }); expect(parse("foo; bar;")).toMatchAst({ ast: program(stmt(simple("foo")), stmt(simple("bar"))), }); }); it("parses pipelines", () => { expect(parse("foo | bar")).toMatchAst({ ast: program( stmt({ type: "Pipeline", commands: [stmt(simple("foo")), stmt(simple("bar"))], }), ), }); expect(parse("foo | bar | baz")).toMatchAst({ ast: program( stmt({ type: "Pipeline", commands: [ stmt(simple("foo")), stmt(simple("bar")), stmt(simple("baz")), ], }), ), }); }); it("parses logical and/or", () => { expect(parse("foo && bar")).toMatchAst({ ast: program( stmt({ type: "Logical", op: "and", left: stmt(simple("foo")), right: stmt(simple("bar")), }), ), }); expect(parse("foo || bar")).toMatchAst({ ast: program( stmt({ type: "Logical", op: "or", left: stmt(simple("foo")), right: stmt(simple("bar")), }), ), }); expect(parse("foo && bar || baz")).toMatchAst({ ast: program( stmt({ type: "Logical", op: "or", left: stmt({ type: "Logical", op: "and", left: stmt(simple("foo")), right: stmt(simple("bar")), }), right: stmt(simple("baz")), }), ), }); }); it("gives pipelines higher precedence than logical ops", () => { expect(parse("foo | bar || baz")).toMatchAst({ ast: program( stmt({ type: "Logical", op: "or", left: stmt({ type: "Pipeline", commands: [stmt(simple("foo")), stmt(simple("bar"))], }), right: stmt(simple("baz")), }), ), }); }); it("parses background commands", () => { expect(parse("foo &\nbar")).toMatchAst({ ast: program(stmt(simple("foo"), true), stmt(simple("bar"))), }); }); }); describe("parse (phase 10: negation)", () => { it("parses negated commands", () => { expect(parse("! foo")).toMatchAst({ ast: program(stmt(simple("foo"), false, true)), }); }); });