Ошибка «мертвого контекста метода» в функции - PullRequest
2 голосов
/ 11 мая 2019

Я пытаюсь написать функцию isBinary, которая проверяет отправленную строку на наличие непечатаемых символов (целое значение вне диапазона 0-127):

isBinary := [ :sline |
    'Reached isBinary fn.' displayNl.
    sline do: [ :char |           "for each character"
        i := char asInteger.      "convert to integer"
        (i < 0 | i > 127) 
        ifTrue: [^true]. ].       "return true if found unprintable"
    ^false. ].                    "if not found above, return false"

(Directory working: '.') allFilesMatching: '*.x'
do: [ :ff |
    ((ff name), ' : ') display.
    infile := FileStream open: ff name mode: FileStream read.
        firstline := infile nextLine.
        (isBinary value: firstline) 
        ifTrue: ['Binary file' displayNl.]
        ifFalse: [ 'Not a binary file' displayNl].
    infile close ].

isBinary достигнута функцияно он выдает следующую ошибку (независимо от того, является ли файл двоичным или нет):

$ gst isbinary.st
"Global garbage collection... done"
/home/abcd/binaryfile.x : Reached isBinary fn.
Object: Character value: 16rC0 error: return from a dead method context
SystemExceptions.BadReturn(Exception)>>signal (ExcHandling.st:254)
SystemExceptions.BadReturn class(Exception class)>>signal (ExcHandling.st:151)
Character(Object)>>badReturnError (Object.st:1389)
String(SequenceableCollection)>>do: (SeqCollect.st:827)
[] in UndefinedObject>>executeStatements (isbinary.st:4)
optimized [] in UndefinedObject>>executeStatements (isbinary.st:16)
[] in Kernel.RecursiveFileWrapper(FilePath)>>filesMatching:do: (FilePath.st:903)
[] in Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:378)
[] in File>>namesDo: (File.st:589)
BlockClosure>>ensure: (BlkClosure.st:268)
File>>namesDo: (File.st:586)
Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:373)
[] in Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:382)
[] in File>>namesDo: (File.st:589)
BlockClosure>>ensure: (BlkClosure.st:268)
File>>namesDo: (File.st:586)
Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:373)
Kernel.RecursiveFileWrapper>>namesDo: (VFS.st:396)
Kernel.RecursiveFileWrapper(FilePath)>>filesMatching:do: (FilePath.st:902)
File(FilePath)>>allFilesMatching:do: (FilePath.st:775)
Directory class>>allFilesMatching:do: (Directory.st:225)
UndefinedObject>>executeStatements (isbinary.st:11)

Замена sline do: на sline asArray do: в моем коде также не работает (та же ошибка).

Где проблема и как это можно решить?Спасибо за вашу помощь.

Редактировать: Как предлагается в ответе и комментариях, я написал следующий код с методом в классе, и это работает.Я просто хочу ваши комментарии, если это правильный метод.

Object subclass: Checker [ 
    isBinary: sline [ 
        'Reached isBinary fn.' displayNl.
        sline do: [ :char |  | i |           "for each character"
            i := char asInteger.             "convert to integer"
            i > 127
            ifTrue: [^true]     "return true if found unprintable"  
        ].       
    ^false. ]      "if no unprintable char found, return false"
].

(Directory working: '.') allFilesMatching: '*.x'
do: [ :ff |
    '------------------------------' displayNl.
    ((ff name), ' : ') displayNl.
    infile := FileStream open: ff name mode: FileStream read.
        firstline := infile nextLine.
        ((Checker new) isBinary: firstline)
        ifTrue: ['Binary file' displayNl.]
        ifFalse: [ 'Not a binary file' displayNl].
    infile close ].

Ответы [ 2 ]

4 голосов
/ 11 мая 2019

Ваша переменная isBinary связана с блоком, который содержит так называемый нелокальный возврат , который не может быть выполнен так, как вы намереваетесь. Причина в том, что семантика нелокального возврата заключается в возврате из метода, который определяет de block (это лексический контекст). Если такого метода не существует или он уже возвращен (другими словами, если лексический контекст отсутствует в стеке вызовов), невозможно определить, куда должен возвращаться поток выполнения. Отсюда и ошибка.

Чтобы решить эту проблему, просто создайте метод #isBinary:, который получает аргумент sline с кодом, который вы написали для блока. Затем вызовите метод вместо оценки блока. Это будет работать.

0 голосов
/ 13 мая 2019

Следующий автономный метод / блочный код работает, создавая возвращаемую переменную, значением которой манипулируют в цикле, если найден непечатаемый символ.Затем цикл завершается:

isBinary := [ :sline |            "WORKS"
    'Reached isBinary fn: ' display.
    ret := false.                 "return variable initialized to false"
    sline do: [ :char |           "loop for each character in sent line"
        i := char asInteger.      "convert to integer"
        i > 127                   "check if printable"
        ifTrue: [ret := true. exit]].   "ret becomes true if found unprintable; does not work if ^ symbol is used"  
    ret].            "if not found above, ret remains false; ret is returned value"

Выше работает без создания класса, как желает OP (me!).

...