в обычном JavaScript в браузере:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE ) {
if(xhr.status == 200){
console.log(xhr.responseText);
} else if(xhr.status == 400) {
console.log('There was an error 400');
} else {
console.log('something else other than 200 was returned');
}
}
}
xhr.open("GET", "mock_data.json", true);
xhr.send();
Или если вы хотите использовать Browserify для объединения ваших модулей с помощью node.js , Вы можете использовать суперагент :
var request = require('superagent');
var url = '/mock_data.json';
request
.get(url)
.end(function(err, res){
if (res.ok) {
console.log('yay got ' + JSON.stringify(res.body));
} else {
console.log('Oh no! error ' + res.text);
}
});
Проблема заключается в том, что вы обращаетесь с NEWLINE
токенами. Это создает конфликт сдвига / уменьшения, который разрешается в пользу действия сдвига. Следствием этого является то, что действие по сокращению конфликта никогда не может быть предпринято, что делает невозможным анализ некоторых грамматических конструкций.
Вот один пример:
else_if_clause_seq: else_if_clause . [$end, NEWLINE, DEDENT]
| else_if_clause . NEWLINE else_if_clause_seq
Это взято из дампа конечного автомата Бизона для той же грамматики. Состояние синтаксического анализатора - это коллекция «элементов»; Каждый предмет - это производство с отмеченной позицией. (Метка - это .
в двух продуктах.) Метка в основном показывает, как далеко продвинулся парсер, когда он достигает этого состояния; если .
находится в конце производства (как в первой строке), то возможно действие сокращения, потому что синтаксический анализатор достиг конца производства. Если .
имеет некоторый следующий символ, то парсер может сдвинуть следующий токен, если следующий токен может быть (или быть первым токеном в некотором расширении) следующим символом. В случае второй продукции, описанной выше, a NEWLINE
можно было бы сдвинуть, если бы это был следующий токен.
Продукция в штате также аннотируется набором преднамеренного просмотра, хотя бизон показывает только набор предварительного просмотра для продукций, которые могут быть уменьшены. Аннотация [$end, NEWLINE, DEDENT]
в конце первого производства - это перспективный набор этого производства. Другими словами, это набор возможных следующих токенов в контексте, в котором производство может быть сокращено.
Это состояние является конфликтом сдвига / уменьшения, потому что NEWLINE
может либо вызвать уменьшение else_if_clause_seq: else_if_clause
, либо его можно сдвинуть в предположении, что NEWLINE else_if_clause_seq
будет проанализирован. Поскольку разрешением конфликта сдвига / уменьшения по умолчанию является предпочтение сдвига (в bison, ply, rply и большинстве других генераторов синтаксического анализатора LR), сокращение никогда не произойдет, что заставит синтаксический анализатор всегда выбирать попытки расширения else_if_clause_seq
, Фактически это означает, что за else_if_clause
, находящимся не в конце блока, всегда должен следовать другой else_if_clause
, что делает невозможным анализ else_if true 1 else 1
, в котором за else_if_clause
следует предложение else
. [тысяча сто пятьдесят-пять] 1156 У парсера, который мог бы смотреть вперед два токена, не было бы проблем с этой грамматикой. Второй следующий токен, следующий за NEWLINE
, должен быть либо else
, либо else_if
; в первом случае требуется уменьшение, а во втором случае сдвиг является правильным действием. Фактически, NEWLINE
действительно не имеет смысла, так как и else
, и else_if
всегда должны предшествовать токены NEWLINE
. Кроме того, поскольку else_if_clause
может заканчиваться только block
, а block
может заканчиваться только DEDENT
, мы можем заключить, что NEWLINE
должен предшествовать DEDENT
.
Похоже, что вы решили отправить NEWLINE
после DEDENT
, поскольку ваша грамматика, кажется, указывает на то, что вы отправили NEWLINE
до и INDENT
. Это, вероятно, работает в теории, но это определенно приводит к конфликтам сдвига / уменьшения, которые вы испытываете.
Более распространенная реализация лексического сканирования с учетом пробелов использует алгоритм , описанный в руководстве по Python : токен NEWLINE
генерируется при обнаружении новой строки, если только окружающие строки не присоединены явно или неявно. и затем принимается решение о выдаче либо одного INDENT
, одного или нескольких DEDENT
с, либо ничего. Тщательное изучение грамматики Python показывает, как это сочетается. Вот упрощенная выдержка в EBNF:
stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: expr_stmt …
compound_stmt: if_stmt …
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
suite
более или менее соответствует вашему block
, но допускает использование однотипных операторов без отступов в одной строке, но обратите внимание, что оно начинается с NEWLINE
. Простые (не составные) операторы заканчиваются на NEWLINE
; составные операторы рассматриваются как самоограниченные.
Альтернативный подход состоит в том, чтобы выдавать токены NEWLINE
только в случае, когда две последовательные строки имеют одинаковый отступ. Как отмечено выше, маркеры NEWLINE
в строках с отступом или с отступом строго избыточны, так как их присутствие может быть выведено; их полное исключение уменьшает количество токенов, которые должны обрабатываться парсером. Но если вы сделаете это, вы больше не сможете использовать простой принцип, согласно которому простые операторы всегда заканчиваются символом NEWLINE
, поскольку за последним простым оператором в block
непосредственно следует DEDENT
. Это делает необходимым использование несколько более сложного (и праворекурсивного) определения expression_seq
:
block : INDENT statement_sequence DEDENT
statement : simple_statement | compound_statement
statement_sequence : statement
| simple_statement NEWLINE statement_sequence
| compound_statement statement_sequence