Compare commits

...

1 Commits

Author SHA1 Message Date
Chris Wanstrath
23642d3da1 import -> use 2025-12-03 15:48:49 -08:00
7 changed files with 58 additions and 58 deletions

View File

@ -25,9 +25,9 @@ ${colors.bright}Commands:${colors.reset}
${colors.cyan}version${colors.reset} Print version ${colors.cyan}version${colors.reset} Print version
${colors.bright}Options:${colors.reset} ${colors.bright}Options:${colors.reset}
${colors.cyan}eval -I${colors.reset} ${colors.yellow}<module>${colors.reset} Import module (can be repeated) ${colors.cyan}eval -U${colors.reset} ${colors.yellow}<module>${colors.reset} Use module (can be repeated)
Example: shrimp -I math -e 'random | echo' Example: shrimp -U math -e 'random | echo'
Example: shrimp -Imath -Istr -e 'random | echo'`) Example: shrimp -Umath -Ustr -e 'random | echo'`)
} }
function showVersion() { function showVersion() {
@ -51,22 +51,22 @@ async function main() {
return return
} }
// Parse -I flags for imports (supports both "-I math" and "-Imath") // Parse -U flags for use (supports both "-U math" and "-Umath")
const imports: string[] = [] const imports: string[] = []
while (args.length > 0) { while (args.length > 0) {
const arg = args[0] const arg = args[0]
if (arg === '-I') { if (arg === '-U') {
// "-I math" format // "-U math" format
if (args.length < 2) { if (args.length < 2) {
console.log(`${colors.bright}error: -I requires a module name${colors.reset}`) console.log(`${colors.bright}error: -I requires a module name${colors.reset}`)
process.exit(1) process.exit(1)
} }
imports.push(args[1]) imports.push(args[1])
args = args.slice(2) args = args.slice(2)
} else if (arg.startsWith('-I')) { } else if (arg.startsWith('-U')) {
// "-Imath" format // "-Umath" format
const moduleName = arg.slice(2) const moduleName = arg.slice(2)
if (!moduleName) { if (!moduleName) {
console.log(`${colors.bright}error: -I requires a module name${colors.reset}`) console.log(`${colors.bright}error: -I requires a module name${colors.reset}`)

View File

@ -496,29 +496,29 @@ describe('Compound assignment operators', () => {
}) })
}) })
describe('import', () => { describe('use', () => {
test('imports single dict', () => { test('uses single dict', () => {
expect(`import str; starts-with? abc a`).toEvaluateTo(true) expect(`use str; starts-with? abc a`).toEvaluateTo(true)
}) })
test('imports multiple dicts', () => { test('uses multiple dicts', () => {
expect(`import str math list; map [1 2 3] do x: x * 2 end`).toEvaluateTo([2, 4, 6]) expect(`use str math list; map [1 2 3] do x: x * 2 end`).toEvaluateTo([2, 4, 6])
}) })
test('imports non-prelude dicts', () => { test('uses non-prelude dicts', () => {
expect(` expect(`
abc = [a=true b=yes c=si] abc = [a=true b=yes c=si]
import abc use abc
abc.b abc.b
`).toEvaluateTo('yes') `).toEvaluateTo('yes')
}) })
test('can specify imports', () => { test('can specify uses', () => {
expect(`import str only=ends-with?; ref ends-with? | function?`).toEvaluateTo(true) expect(`use str only=ends-with?; ref ends-with? | function?`).toEvaluateTo(true)
expect(`import str only=ends-with?; ref starts-with? | function?`).toEvaluateTo(false) expect(`use str only=ends-with?; ref starts-with? | function?`).toEvaluateTo(false)
expect(` expect(`
abc = [a=true b=yes c=si] abc = [a=true b=yes c=si]
import abc only=[a c] use abc only=[a c]
[a c] [a c]
`).toEvaluateTo([true, 'si']) `).toEvaluateTo([true, 'si'])
}) })

View File

@ -57,7 +57,7 @@ export type NodeType =
| 'Star' | 'Star'
| 'Slash' | 'Slash'
| 'Import' | 'Use'
| 'Do' | 'Do'
| 'Underscore' | 'Underscore'
| 'colon' | 'colon'
@ -290,7 +290,7 @@ class SyntaxNodeType {
case 'Slash': case 'Slash':
return term.Slash return term.Slash
case 'Import': case 'Use':
return term.Import return term.Import
case 'Do': case 'Do':

View File

@ -216,8 +216,8 @@ export class Parser {
if (this.is($T.Keyword, 'throw')) if (this.is($T.Keyword, 'throw'))
return this.throw() return this.throw()
if (this.is($T.Keyword, 'import')) if (this.is($T.Keyword, 'use'))
return this.import() return this.use()
return this.expect($T.Keyword, 'if/while/do/import') as never return this.expect($T.Keyword, 'if/while/do/import') as never
} }
@ -705,27 +705,6 @@ export class Parser {
return node.push(this.keyword('end')) return node.push(this.keyword('end'))
} }
import(): SyntaxNode {
const keyword = this.keyword('import')
const args: SyntaxNode[] = []
while (!this.isExprEnd()) {
if (this.is($T.NamedArgPrefix)) {
const prefix = SyntaxNode.from(this.next())
const val = this.value()
const arg = new SyntaxNode('NamedArg', prefix.from, val.to)
arg.push(prefix, val)
args.push(arg)
} else {
args.push(this.identifier())
}
}
const node = new SyntaxNode('Import', keyword.from, args.at(-1)!.to)
node.add(keyword)
return node.push(...args)
}
// if, while, do, etc // if, while, do, etc
keyword(name: string): SyntaxNode { keyword(name: string): SyntaxNode {
const node = SyntaxNode.from(this.expect($T.Keyword, name)) const node = SyntaxNode.from(this.expect($T.Keyword, name))
@ -834,6 +813,27 @@ export class Parser {
return node.push(end) return node.push(end)
} }
use(): SyntaxNode {
const keyword = this.keyword('use')
const args: SyntaxNode[] = []
while (!this.isExprEnd()) {
if (this.is($T.NamedArgPrefix)) {
const prefix = SyntaxNode.from(this.next())
const val = this.value()
const arg = new SyntaxNode('NamedArg', prefix.from, val.to)
arg.push(prefix, val)
args.push(arg)
} else {
args.push(this.identifier())
}
}
const node = new SyntaxNode('Use', keyword.from, args.at(-1)!.to)
node.add(keyword)
return node.push(...args)
}
// while test: blah end // while test: blah end
while(): SyntaxNode { while(): SyntaxNode {
const keyword = this.keyword('while') const keyword = this.keyword('while')

View File

@ -290,7 +290,7 @@ describe('operators', () => {
describe('keywords', () => { describe('keywords', () => {
test('keywords', () => { test('keywords', () => {
expect(`import`).toMatchToken('Keyword', 'import') expect(`use`).toMatchToken('Keyword', 'use')
expect(`end`).toMatchToken('Keyword', 'end') expect(`end`).toMatchToken('Keyword', 'end')
expect(`do`).toMatchToken('Keyword', 'do') expect(`do`).toMatchToken('Keyword', 'do')

View File

@ -2,19 +2,19 @@ import { expect, describe, test } from 'bun:test'
import '../shrimp.grammar' // Importing this so changes cause it to retest! import '../shrimp.grammar' // Importing this so changes cause it to retest!
describe('import', () => { describe('use', () => {
test('parses single import', () => { test('parses single use', () => {
expect(`import str`).toMatchTree(` expect(`use str`).toMatchTree(`
Import Use
keyword import keyword use
Identifier str Identifier str
`) `)
}) })
test('parses multiple imports', () => { test('parses multiple uses', () => {
expect(`import str math list`).toMatchTree(` expect(`use str math list`).toMatchTree(`
Import Use
keyword import keyword use
Identifier str Identifier str
Identifier math Identifier math
Identifier list Identifier list
@ -22,9 +22,9 @@ describe('import', () => {
}) })
test('parses named args', () => { test('parses named args', () => {
expect(`import str only=ends-with?`).toMatchTree(` expect(`use str only=ends-with?`).toMatchTree(`
Import Use
keyword import keyword use
Identifier str Identifier str
NamedArg NamedArg
NamedArgPrefix only= NamedArgPrefix only=

View File

@ -93,7 +93,7 @@ const operators = new Set([
]) ])
const keywords = new Set([ const keywords = new Set([
'import', 'use',
'end', 'end',
'do', 'do',
'if', 'if',