Skip to content

Commit

Permalink
Fix parser (lexer) (#553)
Browse files Browse the repository at this point in the history
* Fix parser

* Add test for REPL `?<command>` help syntax
  • Loading branch information
00vareladavid authored and KristofferC committed Aug 4, 2018
1 parent 484deaf commit f4d0411
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 15 deletions.
24 changes: 14 additions & 10 deletions stdlib/Pkg/src/REPLMode.jl
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ function parse(cmd::String)::Vector{Statement}
# tokenize accoring to whitespace / quotes
qwords = parse_quotes(cmd)
# tokenzie unquoted tokens according to pkg REPL syntax
words::Vector{String} = collect(Iterators.flatten(map(qword2word, qwords)))
words = lex(qwords)
# break up words according to ";"(doing this early makes subsequent processing easier)
word_groups = group_words(words)
# create statements
Expand All @@ -210,7 +210,7 @@ end

# vector of words -> structured statement
# minimal checking is done in this phase
function Statement(words)
function Statement(words)::Statement
is_option(word) = first(word) == '-'
statement = Statement()

Expand Down Expand Up @@ -257,10 +257,16 @@ end

const lex_re = r"^[\?\./\+\-](?!\-) | ((git|ssh|http(s)?)|(git@[\w\-\.]+))(:(//)?)([\w\.@\:/\-~]+)(\.git)(/)? | [^@\#\s;]+\s*=\s*[^@\#\s;]+ | \#\s*[^@\#\s;]* | @\s*[^@\#\s;]* | [^@\#\s;]+|;"x

function qword2word(qword::QuotedWord)
return qword.isquoted ? [qword.word] : map(m->m.match, eachmatch(lex_re, " $(qword.word)"))
# ^
# note: space before `$word` is necessary to keep using current `lex_re`
function lex(qwords::Vector{QuotedWord})::Vector{String}
words = String[]
for qword in qwords
if qword.isquoted
push!(words, qword.word)
else
append!(words, map(m->m.match, eachmatch(lex_re, qword.word)))
end
end
return words
end

function parse_quotes(cmd::String)::Vector{QuotedWord}
Expand All @@ -279,18 +285,16 @@ function parse_quotes(cmd::String)::Vector{QuotedWord}
if in_singlequote # raw char
push!(token_in_progress, c)
else # delimiter
in_doublequote ? push_token!(true) : push_token!(false)
in_doublequote = !in_doublequote
push_token!(true)
end
elseif c == '\''
if in_doublequote # raw char
push!(token_in_progress, c)
else # delimiter
in_singlequote ? push_token!(true) : push_token!(false)
in_singlequote = !in_singlequote
push_token!(true)
end
elseif c == ' ' && !(in_doublequote || in_singlequote)
push_token!(false)
else
push!(token_in_progress, c)
end
Expand Down
12 changes: 7 additions & 5 deletions stdlib/Pkg/test/repl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ temp_pkg_dir() do project_path
end

@testset "tokens" begin
statement = Pkg.REPLMode.parse("?dev")[1]
@test statement.command.kind == Pkg.REPLMode.CMD_HELP
@test length(statement.arguments) == 1
@test statement.arguments[1] == "dev"
statement = Pkg.REPLMode.parse("add [email protected]:JuliaLang/Example.jl.git")[1]
@test "add" in statement.command.names
@test statement.arguments[1] == "[email protected]:JuliaLang/Example.jl.git"
Expand Down Expand Up @@ -844,11 +848,9 @@ end
@test qwords[1].isquoted
@test qwords[1].word == "Don't"
@test !qwords[2].isquoted
@test qwords[2].word == "forget"
@test !qwords[3].isquoted
@test qwords[3].word == "to"
@test qwords[4].isquoted
@test qwords[4].word == "\"test\""
@test qwords[2].word == " forget to "
@test qwords[3].isquoted
@test qwords[3].word == "\"test\""
@test_throws CommandError Pkg.REPLMode.parse_quotes("Don't")
@test_throws CommandError Pkg.REPLMode.parse_quotes("Unterminated \"quot")
end
Expand Down

0 comments on commit f4d0411

Please sign in to comment.