Skip to content

Add support for simple import *statement* to identifier #2

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

Merged
merged 5 commits into from
Aug 1, 2016
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
31 changes: 28 additions & 3 deletions src/grammar.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ grammar =
o 'Return'
o 'Comment'
o 'STATEMENT', -> new StatementLiteral $1
o 'Import'
o 'Export'
]

# All the different types of expressions in our language. The basic unit of
Expand All @@ -117,8 +119,6 @@ grammar =
o 'Class'
o 'Throw'
o 'Yield'
o 'Import'
o 'Export'
]

Yield: [
Expand Down Expand Up @@ -351,8 +351,33 @@ grammar =
o 'CLASS SimpleAssignable EXTENDS Expression Block', -> new Class $2, $4, $5
]

NamedImports: [
o '{ }', -> new ImportsList []
o '{ ImportsList OptComma }', -> new ImportsList $2
]

ImportClause: [
o 'NamedImports'
o 'ImportSpecifier'
o '* IMPORT_AS Identifier'
]

ImportSpecifier: [
o 'Identifier'
o 'Identifier IMPORT_AS Identifier', -> new ImportSpecifier $1, $3
]

ImportsList: [
o 'ImportSpecifier', -> [$1]
o 'ImportsList , ImportSpecifier', -> $1.concat $3
o 'ImportsList OptComma TERMINATOR ImportSpecifier', -> $1.concat $4
o 'INDENT ImportsList OptComma OUTDENT', -> $2
o 'ImportsList OptComma INDENT ImportsList OptComma OUTDENT', -> $1.concat $4
]

Import: [
o 'IMPORT Expression', -> new Import $2
o 'IMPORT String', -> new Import $2
o 'IMPORT ImportClause IMPORT_FROM String', -> new Import $4, $2
]

# Ordinary function invocation, or a chained series of calls.
Expand Down
22 changes: 21 additions & 1 deletion src/lexer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ exports.Lexer = class Lexer
@ends = [] # The stack for pairing up tokens.
@tokens = [] # Stream of parsed tokens in the form `['TYPE', value, location data]`.
@seenFor = no # Used to recognize FORIN and FOROF tokens.
@seenImport = no # Used to recognize IMPORT FROM? AS? tokens.

@chunkLine =
opts.line or 0 # The start line for the current @chunk.
Expand Down Expand Up @@ -113,7 +114,22 @@ exports.Lexer = class Lexer
if id is 'from' and @tag() is 'YIELD'
@token 'FROM', id
return id.length

if id is 'import'
@seenImport = yes
@token 'IMPORT', id, 0, idLength
return idLength

if id is 'from' and @seenImport
@token 'IMPORT_FROM', id
return idLength

if id is 'as' and @seenImport
@token 'IMPORT_AS', id
return idLength

[..., prev] = @tokens

tag =
if colon or prev? and
(prev[0] in ['.', '?.', '::', '?::'] or
Expand Down Expand Up @@ -317,9 +333,13 @@ exports.Lexer = class Lexer
lineToken: ->
return 0 unless match = MULTI_DENT.exec @chunk
indent = match[0]

@seenFor = no
@seenImport = no

size = indent.length - 1 - indent.lastIndexOf '\n'
noNewlines = @unfinished()

if size - @indebt is @indent
if noNewlines then @suppressNewlines() else @newlineToken 0
return indent.length
Expand Down Expand Up @@ -774,7 +794,7 @@ JS_KEYWORDS = [
'return', 'throw', 'break', 'continue', 'debugger', 'yield'
'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally'
'class', 'extends', 'super'
'export', 'import', 'default'
'export', 'import', 'from', 'default'
]

# CoffeeScript-only keywords.
Expand Down
55 changes: 52 additions & 3 deletions src/nodes.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -1226,18 +1226,67 @@ exports.Class = class Class extends Base
#### Import

exports.Import = class Import extends Base
constructor: (@expression) ->
constructor: (@expression, @identifier) ->

children: ['expression']
children: ['expression', 'identifier']

isStatement: YES
jumps: NO

makeReturn: THIS

compileNode: (o) ->
[].concat @makeCode(@tab + 'import '), @expression.compileToFragments(o), @makeCode(';')
code = []

code.push @makeCode(@tab + 'import ')

if @identifier
if @identifier.value?
code.push @makeCode("#{@identifier.value} from ")
else
code.push fragment for fragment in @identifier.compileNode(o)
code.push @makeCode(' from ')

if @expression.value?
code.push @makeCode(@expression.value)

code.push @makeCode(';')
code

exports.ImportsList = class ImportsList extends Base
constructor: (identifiers) ->
@identifiers = identifiers or []

children: ['identifiers']

compileNode: (o) ->
return [@makeCode('[]')] unless @identifiers.length

o.indent += TAB

code = []
compiledList = (identifier.compileToFragments o, LEVEL_LIST for identifier in @identifiers)

for fragments, index in compiledList
code.push @makeCode(', ') if index
code.push fragments...

if fragmentsToText(code).includes('\n')
code.unshift @makeCode("{\n#{o.indent}")
code.push @makeCode("\n#{@tab}}")
else
code.unshift @makeCode("{ ")
code.push @makeCode(" }")

code

exports.ImportSpecifier = class ImportSpecifier extends Base
constructor: (@original, @alias) ->

children: ['from', 'as']

compileNode: (o) ->
return [@makeCode("#{@original.value} as #{@alias.value}")]

#### Assign

Expand Down
45 changes: 25 additions & 20 deletions test/modules.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,35 @@ test "import module", ->
# console.log toJS input
eq toJS(input), output

# test "module import test, syntax #1", ->
# input = "import foo from 'lib'"
# output = "import foo from 'lib';"
# eq toJS(input), output
test "module import test, syntax #1", ->
input = "import foo from 'lib'"
output = "import foo from 'lib';"
eq toJS(input), output

# test "module import test, syntax #2", ->
# input = "import { foo } from 'lib'"
# output = "import { foo } from 'lib';"
# eq toJS(input), output
test "module import test, syntax #2", ->
input = "import { foo } from 'lib'"
output = "import { foo } from 'lib';"
eq toJS(input), output
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also remember to add tests for invalid stuff (in test/error_messages.coffee).


# test "module import test, syntax #3", ->
# input = "import { default as foo } from 'lib'"
# output = "import { default as foo } from 'lib';"
# eq toJS(input), output
test "module import test, syntax #3", ->
input = "import { bar as foo } from 'lib'"
output = "import { bar as foo } from 'lib';"
eq toJS(input), output

# test "module import test, syntax #4", ->
# input = "import { square, diag } from 'lib'"
# output = "import { square, diag } from 'lib';"
# eq toJS(input), output
test "module import test, syntax #3", ->
input = "import { oof, bar as foo } from 'lib'"
output = "import { oof, bar as foo } from 'lib';"
eq toJS(input), output

# test "module import test, syntax #5", ->
# input = "import { foo } from 'lib' # with a comment"
# output = "import { foo } from 'lib' ;"
# eq toJS(input), output
test "module import test, syntax #4", ->
input = "import { square, diag } from 'lib'"
output = "import { square, diag } from 'lib';"
eq toJS(input), output

test "module import test, syntax #5", ->
input = "import { foo } from 'lib' # with a comment"
output = "import { foo } from 'lib';"
eq toJS(input), output

# test "module export test, syntax #1", ->
# input = "export default mixin"
Expand Down